diff --git a/.rubocop.yml b/.rubocop.yml index 3134bfe..84b32c7 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -38,6 +38,9 @@ Layout/LineLength: Layout/SpaceInsideHashLiteralBraces: EnforcedStyle: space +Lint/NonLocalExitFromIterator: + Enabled: false + Metrics/ClassLength: Max: 250 Metrics/MethodLength: diff --git a/Gemfile.lock b/Gemfile.lock index 819ce01..f7fae70 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,6 +3,7 @@ PATH specs: rubocop-obsession (0.1.0) activesupport + rubocop (~> 1.41) GEM remote: https://rubygems.org/ diff --git a/config/default.yml b/config/default.yml new file mode 100644 index 0000000..3f94440 --- /dev/null +++ b/config/default.yml @@ -0,0 +1,163 @@ +Obsession/MethodOrder: + Enabled: true +Obsession/NoBreakOrNext: + Enabled: false + Exclude: + - 'script/db/**/*' +Obsession/NoParagraphs: + Enabled: false + Exclude: + - 'db/migrate/*' + - 'spec/**/*' +Obsession/NoTodos: + Enabled: false +Obsession/TooManyParagraphs: + Enabled: false + Exclude: + - 'db/migrate/*' + - 'script/db/**/*' + - 'spec/**/*' + +Obsession/Graphql/MutationName: + Enabled: true + Include: + - 'app/graphql/mutations/**/*' + +Obsession/Rspec/DescribePublicMethod: + Enabled: true + Include: + - 'spec/**/*_spec.rb' +# Uncommenting this would mean adding rubocop-rspec as a gem dependency. Feels like too much for now. +# Obsession/Rspec/EmptyLineAfterFinalLet: +# Enabled: true +# Include: +# - 'spec/**/*' + +Obsession/Rails/CallbackOneMethod: + Enabled: true + Include: + - 'app/models/**/*' + - 'app/controllers/**/*' +Obsession/Rails/FullyDefinedJsonField: + Enabled: true + Include: + - 'db/migrate/*' +Obsession/Rails/MigrationBelongsTo: + Enabled: true + Include: + - 'db/migrate/*' +Obsession/Rails/NoCallbackConditions: + Enabled: true + Include: + - 'app/models/**/*' +Obsession/Rails/PrivateCallback: + Enabled: true + Include: + - 'app/models/**/*' + - 'app/controllers/**/*' +Obsession/Rails/SafetyAssuredComment: + Enabled: false + Include: + - 'db/migrate/*' +Obsession/Rails/ServiceName: + Enabled: true + Include: + - 'app/services/**/*' + - 'app/jobs/**/*' + Exclude: + - 'app/jobs/application_job.rb' + - 'app/jobs/scheduled/scheduled_job.rb' + - '**/*events/**' +Obsession/Rails/ServicePerformMethod: + Enabled: true + Include: + - 'app/services/**/*' +Obsession/Rails/ShortAfterCommit: + Enabled: true + Include: + - 'app/models/**/*' +Obsession/Rails/ShortValidate: + Enabled: true + Include: + - 'app/models/**/*' +Obsession/Rails/ValidateOneField: + Enabled: true + Include: + - 'app/models/**/*' +Obsession/Rails/ValidationMethodName: + Enabled: true + Include: + - 'app/models/**/*' + +Layout/ClassStructure: + Enabled: true + AutoCorrect: false + Categories: + module_inclusion: + - include + - prepend + - extend + attributes: + - attribute + - attr_reader + - attr_writer + - attr_accessor + - alias_attribute + - delegate + - enum + associations: + - belongs_to + - has_one + - has_many + - has_and_belongs_to_many + validations: + - validates + - validate + - validates_with + callbacks: + - before_validation + - before_save + - before_create + - before_destroy + - after_initialize + - after_create + - after_save + - after_destroy + - after_commit + - after_create_commit + - after_update_commit + - after_destroy_commit + - around_create + other_macros: + - devise + - acts_as_paranoid + - serialize + - has_paper_trail + - audited + scopes: + - default_scope + - scope + controller_actions: + - before_action + - skip_before_action + controller_rescue: + - rescue_from + ExpectedOrder: + - module_inclusion + - constants + - attributes + - enums + - associations + - validations + - callbacks + - other_macros + - scopes + - controller_macros + - controller_actions + - controller_action_caching + - controller_rescue + - class_methods + - initializer + - public_methods + - protected_methods + - private_methods diff --git a/lib/rubocop/cop/mixin/files/verbs.txt b/lib/rubocop/cop/mixin/files/verbs.txt new file mode 100644 index 0000000..0a7fda9 --- /dev/null +++ b/lib/rubocop/cop/mixin/files/verbs.txt @@ -0,0 +1,8507 @@ +abandon +abase +abash +abate +abbreviate +abdicate +abduct +abet +abhor +abide +abirritate +abjure +ablate +abnegate +abolish +abominate +abort +abound +about-ship +about-turn +aboutface +abrade +abreact +abridge +abrogate +abscess +abscise +abscond +abseil +absent +absolve +absorb +absquatulate +abstain +abstract +abuse +abut +abye +accede +accelerate +accent +accentuate +accept +access +accession +acclaim +acclimatize +accommodate +accompany +accomplish +accord +accost +account +accoutre +accredit +accrete +accrue +acculturate +accumulate +accuse +accustom +acerbate +acetify +acetylate +ache +achieve +achromatize +acidify +acidulate +acierate +acknowledge +acquaint +acquiesce +acquire +acquit +act +activate +actualize +actuate +acuminate +adapt +add +addict +addle +address +adduce +adduct +adhere +adhibit +adjoin +adjourn +adjudge +adjudicate +adjure +adjust +adlib +admeasure +administer +administrate +admire +admit +admix +admonish +adopt +adore +adorn +adsorb +adulate +adulterate +adumbrate +advance +advantage +adventure +advert +advertize +advise +advocate +aerate +aerify +aestivate +affect +affiance +affiliate +affirm +affix +afflict +afford +afforest +affranchise +affray +affright +affront +africanize +afrikanerize +age +agglomerate +agglutinate +aggrade +aggrandize +aggravate +aggregate +aggress +aggrieve +agist +agitate +agonize +agree +aid +ail +aim +air +aircondition +aircool +airdrop +airdry +airlift +airmail +alarm +albumenize +alchemize +alcoholize +alert +alibi +alien +alienate +alight +aliment +aline +alit +alkalify +alkalize +allay +allege +allegorize +alleviate +alliterate +allocate +allot +allow +allowance +alloy +allude +allure +ally +alphabetize +alter +altercate +alternate +aluminize +amalgamate +amass +amaze +amble +ambulate +ambuscade +ambush +ameliorate +amend +amerce +americanize +ammoniate +ammonify +amnesty +amortize +amount +amplify +amputate +amuse +anagrammatize +analogize +analyze +anastomose +anathematize +anatomize +anchor +anele +anesthetize +anger +angle +angle-park +anglicize +anglify +anguish +angulate +animadvert +animalize +animate +ankylose +anneal +annex +annihilate +annotate +announce +annoy +annualize +annul +annunciate +anodize +anoint +answer +antagonize +ante +antecede +antedate +antevert +anthologize +anthropomorphize +anticipate +antiquate +antique +ape +aphorize +apocopate +apologize +apostatize +apostrophize +apotheosize +appall +appeal +appear +appease +append +apperceive +appertain +applaud +appliqu_e +apply +appoint +apportion +appose +appraise +appreciate +apprehend +apprentice +apprize +approach +approbate +appropriate +approve +approximate +apron +aquaplane +aquatint +arbitrate +arc +arch +archaize +argue +argufy +arise +arm +armour +aromatize +arouse +arraign +arrange +array +arrest +arrive +arrogate +arterialize +article +articulate +artificialize +aryanize +ascend +ascertain +ascribe +ask +asperse +asphalt +asphyxiate +aspirate +aspire +assail +assassinate +assault +assay +assemble +assent +assert +assess +asseverate +assibilate +assign +assimilate +assist +associate +assoil +assort +assuage +assume +assure +asterisk +astonish +astound +astrict +atomize +atone +atrophy +attach +attack +attain +attaint +attemper +attempt +attend +attenuate +attest +attire +attitudinize +attorn +attract +attribute +attune +auction +auctioneer +audit +audition +augment +augur +auscultate +auspicate +australianize +authenticate +authorize +autoclave +autograph +autolyze +automate +automatize +autotomize +avail +avalanche +avenge +aver +average +avert +aviate +avoid +avouch +avow +await +awake +awaken +award +awe +axe +azotize +baa +babbitt +babble +baby +babysit +back +backbite +backcomb +backcross +backdate +backfill +backfire +backhand +backpedal +backslide +backspace +backstitch +backstroke +backtrack +backwash +backwater +badger +badmouth +baffle +bag +bail +bait +baize +bake +baksheesh +balance +bale +balkanize +ball +ballast +balloon +ballot +ballyhoo +ballyrag +bamboozle +ban +band +bandage +bandy +bang +banish +bankroll +bankrupt +banquet +bant +banter +baptize +bar +barbarize +barber +barde +bare +bargain +barge +bark +barnstorm +barr_e +barrack +barrage +barrel +barrel-roll +barricade +barter +base +bash +basify +bask +basset +bastardize +baste +bastinado +bat +batch +bate +batfowl +bath +bathe +batten +batter +battle +battledore +baulk +bawl +bay +bayonet +be +beach +beacon +bead +beagle +beam +bear +beard +beat +beatify +beautify +beaver +bechance +beckon +becloud +become +bed +bedaub +bedazzle +bedeck +bedevil +bedew +bedight +bedim +bedizen +bedraggle +beef +beep +beeswax +beetle +befall +befit +befog +befool +befoul +befriend +befuddle +beg +beget +beggar +begin +begird +begrime +begrudge +beguile +behave +behead +behold +behove +bejewel +belabour +belay +belch +beleaguer +belie +believe +belittle +bell +bellow +belly +belly-laugh +bellyache +bellyache +bellyland +belong +belt +bemean +bemire +bemoan +bemuse +bename +bench +bend +benefice +benefit +benumb +bequeath +berate +bereave +bereft +berry +berth +beseech +beseem +beset +beshrew +besiege +besmear +besmirch +bespangle +bespatter +bespeak +bespread +besprinkle +best +besteaded +bestialize +bestir +bestow +bestrew +bestride +bet +betake +bethink +betide +betoken +betray +betroth +better +bewail +beware +bewilder +bewitch +bewray +bias +bicker +bicycle +bid +bide +biff +bifurcate +big-note +bight +bike +bilge +bilk +bill +billet +bin +bioassay +birch +bird's-nest +birddog +birdlime +birdy +birl +birr +birth +bisect +bit +bitch +bite +bitter +bituminize +bivouac +blab +blabber +black-lead +blackball +blackbird +blacken +blackguard +blackjack +blackleg +blacklist +blackmail +blackmarket +blackout +blah +blame +blanch +blandish +blank +blanket +blare +blarney +blaspheme +blast +blat +blather +blaze +blazon +bleach +blear +bleat +bleed +bleep +blemish +blench +blend +blent +bless +blest +blether +blight +blind +blindfold +blink +blip +blister +blitz +bloat +blob +block +blockade +blood +bloody +bloom +blossom +blot +blotch +blouse +blow +blow-wave +blowdry +blub +blubber +bludge +bludgeon +blue +bluepencil +blueprint +bluff +blunder +blunge +blunt +blur +blurt +blush +bluster +board +boast +boat +bob +bobol +bobsleigh +bode +bodge +body +bodycheck +boggle +bogie +boil +bolster +bomb +bombard +bond +bone +bong +boo +boob +booby-trap +boodle +boogie +boohoo +book +boom +boomerang +boondoggle +boost +boot +bootleg +bootlick +booze +bop +borate +border +bore +borrow +bosom +boss +botanize +botch +bother +bottle +bottlefeed +bottleneck +bottom +boult +bounce +bound +bound +bow +bowdlerize +bowl +bowse +bowwow +box +boxhaul +boycott +brabble +brace +brachiate +bracket +brag +brail +braille +brain +brainwash +braise +brake +bramble +branch +brand +brandish +brattice +brave +brawl +bray +braze +brazen +breach +bread +break +breakaway +breakfast +bream +breast +breastfeed +breathalyze +breathe +brede +breech +breed +breeze +brevet +brew +brey +bribe +brick +bridge +bridle +brief +brigade +brighten +brim +brine +bring +briquette +bristle +broach +broadcast +broaden +brocade +broddle +broider +broil +bromate +brominate +bronze +brood +brook +browbeat +brown +browse +bruise +bruit +brush +brutalize +brutify +bubble +buck +bucket +buckle +buckler +buckram +bud +buddle +budge +budget +buffalo +buffer +buffer +buffet +bug +bugger +bugle +build +bulge +bulk +bull +bulldoze +bulletin +bulletproof +bullshit +bullwhip +bully +bullyrag +bulwark +bum +bumble +bump +bump-start +bumper +bunch +bundle +bung +bungle +bunk +bunker +bunko +bunt +buoy +bur +burble +burden +bureaucratize +burgeon +burglarize +burgle +burke +burl +burlesque +burn +burnish +burp +burrow +burst +burthen +bury +bus +bush +bushel +bushwhack +busk +bust +bustle +busy +butcher +butt +butter +button +buttonhole +buttress +buy +buzz +bypass +bypass +cabal +cabbage +cable +cachinnate +cackle +caddy +cadge +cage +cagmag +cajole +cake +calcify +calcine +calculate +calendar +calender +calibrate +calk +call +calliper +callous +callus +calm +calque +calumniate +calve +camber +camouflage +camp +campaign +camphorate +can +canal +canalize +cancel +candle +candy +cane +canker +cannibalize +cannon +cannonade +cannonball +canoe +canonize +canoodle +canopy +canter +canter +cantilever +cantillate +canton +canulate +canvass +cap +capacitate +caparison +caper +capitalize +capitulate +caponize +capriole +capsize +capsulize +captain +caption +captivate +capture +caramelize +caravan +carbolize +carbonado +carbonate +carbonize +carburet +carburize +card +care +careen +career +caress +caricature +carillon +cark +carnify +carny +carol +carouse +carp +carpenter +carpet +carry +cartelize +carve +cascade +case +caseate +casefy +caseharden +cash +cashier +casserole +cast +castigate +castle +castoff +castrate +cat +catalogue +catalyze +catapult +catcall +catch +catechize +categorize +catenate +cater +caterwaul +catheterize +catholicize +catnap +caucus +caulk +cause +cauterize +caution +cave +cavern +cavil +cavort +caw +caway +cease +cede +ceil +celebrate +cellar +cement +cense +censor +censure +centralize +centre +centrifuge +centuplicate +cere +cerebrate +certificate +certify +cess +chafe +chaff +chaffer +chagrin +chain +chain-stitch +chainreact +chainsmoke +chair +chalk +challenge +chamber +chamfer +chamois +champ +champion +chance +chandelle +change +changeover +channel +channelize +chant +chap +chaperone +chapter +char +character +characterize +charcoal +charge +charm +chart +charter +chase +chass_e +chasten +chastise +chat +chatter +chauffeur +chaw +cheapen +cheat +check +checker +checkmate +checkrow +cheek +cheep +cheer +cheese +chelate +chelp +chemosorb +chequer +cherish +chevy +chew +chiack +chicane +chide +chill +chime +chin +chine +chink +chip +chirm +chirp +chirre +chirrup +chisel +chitchat +chitter +chivy +chlorinate +chock +choke +chomp +chondrify +choose +chop +chord +choreograph +chortle +chorus +christen +christianize +chrome +chronicle +chuck +chuckle +chuff +chug +chum +chump +chunder +chunter +church +churn +churr +chute +chyack +cicatrize +cinch +cinchonize +cinder +cinematograph +cipher +circle +circuit +circularize +circulate +circumambulate +circumcise +circumfuse +circumnavigate +circumnutate +circumscribe +circumstantiate +circumvallate +circumvent +cite +cityfy +civilize +clack +clad +claim +clam +clamber +clamour +clamp +clang +clangour +clank +clap +clapboard +clapperclaw +clarify +clarion +clash +clasp +class +classicize +classify +clatter +claver +claw +clay +clean +cleanse +clear +cleat +cleave +cleck +cleft +clem +clench +clepe +clerk +clew +click +climax +climb +clinch +cling +clink +clinker +clip +cloak +clobber +clock +clog +cloister +clomb +clomp +clonk +clop +close +closet +closure +clot +clothe +cloture +cloud +clout +clown +cloy +club +clubhaul +cluck +clue +clump +clunk +cluster +clutch +clutter +clype +co-edit +coach +coagulate +coal +coalesce +coarsen +coast +coat +coauthor +coax +cob +cobble +cocainize +cock +cocker +cockle +cocknify +cocoon +cod +coddle +code +codename +codify +coedit +coerce +coexist +coextend +coextrude +coff +coffer +cofound +cog +cogitate +cognize +cohabit +cohere +cohobate +coif +coiffure +coil +coin +coincide +coinsure +coke +cold +coldshoulder +coldweld +collaborate +collapse +collar +collate +collect +collectivize +collet +collide +colligate +collimate +collocate +collogue +collude +colly +colonize +colorcode +colour +comanage +comb +combat +combine +combust +come +comfort +command +commandeer +commeasure +commemorate +commence +commend +comment +commentate +commercialize +commingle +comminute +commiserate +commission +commit +commix +commove +communalize +commune +communicate +communize +commutate +commute +comp`ere +compact +companion +company +compare +compartmentalize +compass +compel +compensate +compere +compete +compile +complain +complect +complement +complete +complicate +compliment +complot +comply +comport +compose +compost +compound +comprehend +compress +comprise +compromise +compute +computerize +concatenate +concave +conceal +concede +conceive +concelebrate +concentrate +concentre +conceptualize +concern +concertina +concertize +conciliate +conclude +concoct +concrete +concretize +concur +concuss +condemn +condense +condescend +condition +condole +condone +conduce +conduct +cone +confab +confabulate +confect +confederate +confer +confess +confide +configure +confine +confirm +confiscate +conflate +conflict +conform +confound +confront +confuse +confute +conga +congeal +congest +conglobate +conglomerate +conglutinate +congratulate +congregate +conjecture +conjoin +conjugate +conjure +conk +conn +connect +connive +connote +conquer +conscript +consecrate +consent +conserve +consider +consign +consist +consociate +console +consolidate +consort +conspire +constellate +consternate +constipate +constitute +constitutionalize +constrain +constrict +constringe +construct +construe +consubstantiate +consult +consume +consummate +contact +contain +containerize +contaminate +contango +contemn +contemplate +contemporize +contend +content +contest +contextualize +continue +contort +contour +contract +contradict +contradistinguish +contraindicate +contrast +contravene +contribute +contrive +control +controvert +contuse +convalesce +convene +conventionalize +converge +converse +convert +convex +convey +convict +convince +convoke +convolute +convolve +convoy +convulse +coo +cooey +cook +cool +coop +cooper +cooperate +coopt +coordinate +cop +cope +copolymerize +copper +copper-bottom +coproduce +copulate +copy +copyedit +copyread +copyright +coquet +corbel +cord +cordon +core +cork +corkscrew +corn +corner +cornice +corrade +corral +correct +correlate +correspond +corrival +corroborate +corrode +corrugate +corrupt +corset +coruscate +cosh +cosher +cosponsor +cosset +cost +costar +costume +cote +cotter +couch +cough +counsel +count +countenance +counter +counteract +counterattack +counterattack +counterbalance +counterchange +countercharge +counterclaim +counterfeit +countermand +countermarch +countermine +countermove +counterplot +counterpoise +counterproposal +counterpunch +countersign +countersink +countervail +counterweigh +couple +course +court +courtmartial +cove +covenant +cover +coverup +covet +cow +cower +cowk +cowl +cowp +cox +cozen +crab +crack +crackle +cradle +craft +cram +cramp +crane +crank +crap +crash +crash-dive +crashland +crate +crater +craunch +crave +crawl +crayon +craze +creak +cream +crease +create +credit +creep +cremate +crenellate +crepe +crepitate +crescendo +crevasse +crew +crib +crick +criminalize +criminate +crimp +crimple +crimson +cringe +crinkle +cripple +crisp +crisscross +criticize +croak +crochet +crock +crook +croon +crop +croquet +cross +cross-breed +cross-fade +crossbred +crosscheck +crosscheck +crosscut +crossexamine +crossfertilize +crosshatch +crossindex +crosspollinate +crossquestion +crossrefer +crossreference +crossruff +crossstitch +crouch +croup +crow +crowd +crown +crucify +cruise +crumb +crumble +crump +crumple +crunch +crusade +crush +crust +crutch +cry +crystallize +cub +cube +cuckold +cuckoo +cuddle +cudgel +cue +cuff +cuirass +cull +culminate +cultivate +culture +cumber +cumulate +cup +cupel +curarize +curb +curd +curdle +cure +curette +curl +curry +curse +curtail +curtain +curtsy +curve +curvet +cushion +customize +cut +cutback +cutinize +cwtch +cybernate +cycle +cyclostyle +cypher +dab +dabble +dado +daff +dag +dagger +dally +dam +damage +damascene +damask +damn +damnify +damp +dampen +dance +dander +dandify +dandle +dangle +dap +dapple +dare +dark +darken +darkle +darn +dart +dash +date +dateline +daub +daunt +dawdle +dawn +day-dream +daydream +daze +dazzle +de-horn +deactivate +deaden +deadhead +deadlock +deafen +deal +deaminize +debag +debar +debark +debase +debate +debauch +debilitate +debit +debouch +debrief +debug +debunk +debus +debut +decaffeinate +decal +decalcify +decamp +decant +decapitate +decarbonate +decarbonize +decarburize +decay +decease +deceive +decelerate +decentralize +decerebrate +decern +decertify +decide +decimalize +decimate +decipher +deck +declaim +declare +declass +declassify +decline +declutch +decoct +decode +decoke +decollate +decolonize +decolour +decompose +decompound +decompress +deconsecrate +decontaminate +decontrol +decorate +decorticate +decoy +decrease +decree +decrepitate +decribe +decry +decrypt +decuple +decussate +dedicate +deduce +deduct +deed +deek +deem +deemphasize +deepen +deepfreeze +deepfry +deepsix +deescalate +deface +defalcate +defame +default +defeat +defecate +defect +defend +defer +defilade +defile +define +deflagrate +deflate +deflect +deflocculate +deflower +defoliate +deforce +deforest +deform +defraud +defray +defrock +defrost +defuze +defy +degas +degauss +degenerate +deglutinate +degrade +degrease +degustate +dehisce +dehorn +dehumanize +dehumidify +dehydrate +dehydrogenize +dehypnotize +deice +deify +deign +deject +delaminate +delate +delay +dele +delete +deliberate +delight +delimitate +delineate +deliquesce +deliver +delocalize +delouse +delude +deluge +delve +demagnetize +demagogue +demand +demarcate +dematerialize +demean +dement +demilitarize +demineralize +demise +demist +demit +demob +demobilize +democratize +demodulate +demolish +demonetize +demonize +demonstrate +demoralize +demote +demount +demulsify +demur +demystify +demythologize +den +denationalize +denaturalize +denaturize +denazify +denigrate +denitrate +denitrify +denizen +denominate +denote +denounce +dent +denuclearize +denudate +denude +denunciate +deny +deodorize +deoxidize +deoxygenize +depart +departmentalize +depasture +depend +depersonalize +depict +depicture +depilate +deplane +deplete +deplore +deploy +deplume +depolarize +depoliticize +depolymerize +depone +depopulate +deport +depose +deposit +deprave +deprecate +depreciate +depredate +depress +depressurize +deprive +depurate +depute +deputize +deracinate +deraign +derail +derange +derate +deration +deregister +derequisition +derestrict +deride +derive +derogate +derrick +desalinize +desalt +descale +descant +descend +deschool +describe +descry +desecrate +desegregate +desensitize +desert +deserve +desexualize +desiccate +desiderate +design +designate +desire +desist +desolate +desorb +despair +despatch +despise +despite +despoil +despond +despumate +desquamate +destine +destroy +destruct +desulphurize +detach +detail +detain +detect +deter +deterge +deteriorate +determine +detest +dethrone +detonate +detour +detoxicate +detoxify +detract +detrain +detribalize +detrude +detruncate +deuterate +devalue +devastate +develop +devest +deviate +devil +devise +devitalize +devitrify +devoice +devolve +devote +devour +dew +diabolize +diadem +diagnose +diagram +dial +dialogize +dialogue +dialyze +diamond +diaper +diazotize +dib +dibble +dice +dichotomize +dicker +dictate +diddle +die +die-cast +diet +differ +differentiate +diffract +diffuse +dig +digest +dight +digitalize +digitize +dignify +digress +dike +dilapidate +dilate +dillydally +dilute +dim +dimension +dimidiate +diminish +dimple +din +dine +ding +dint +dip +diphthongize +direct +dirk +dirty +disable +disabuse +disaccord +disaccredit +disaccustom +disadvantage +disaffect +disaffiliate +disaffirm +disafforest +disagree +disallow +disambiguate +disannul +disappear +disappoint +disapprove +disarm +disarrange +disarray +disarticulate +disassemble +disassociate +disavow +disband +disbar +disbelieve +disbranch +disbud +disburden +disburse +disc +discant +discard +discern +discharge +discipline +disclaim +disclose +discolour +discombobulate +discomfit +discomfort +discommend +discommode +discommon +discompose +disconcert +disconnect +disconsider +discontent +discontinue +discord +discount +discountenance +discourage +discourse +discover +discredit +discriminate +discuss +disdain +disembark +disembarrass +disembody +disembogue +disembowel +disembroil +disenable +disenchant +disencumber +disendow +disenfranchise +disengage +disentail +disentangle +disenthrall +disentitle +disentomb +disentwine +disestablish +disesteem +disfavour +disfeature +disfigure +disforest +disfranchise +disfrock +disgorge +disgrace +disgruntle +disguise +disgust +dish +dishearten +dishevel +dishonour +disillusion +disincline +disinfect +disinfest +disinherit +disintegrate +disinter +disinterest +disject +disjoin +disjoint +dislike +dislimn +dislocate +dislodge +dismantle +dismast +dismay +dismember +dismiss +dismount +disobey +disoblige +disorder +disorganize +disorientate +disown +disparage +dispatch +dispel +dispend +dispense +disperse +dispirit +displace +displant +display +displease +displeasure +displode +disport +dispose +dispossess +dispraise +disprize +disproportion +disproportionate +disprove +dispute +disqualify +disquiet +disrate +disregard +disrelish +disremember +disrespect +disrobe +disrupt +dissatisfy +dissect +disseize +dissemble +disseminate +dissent +dissertate +disserve +dissever +dissimilate +dissimulate +dissipate +dissociate +dissolve +dissuade +distance +distaste +distemper +distend +distill +distinguish +distort +distract +distrain +distress +distribute +district +distrust +disturb +disunite +ditch +dither +ditto +divagate +divaricate +dive +divebomb +diverge +diversify +divert +divest +divide +divine +divinize +divorce +divulgate +divulge +divvy +dizen +dizzy +do +dock +docket +doctor +document +dodder +dodge +doff +dog +dog-paddle +dogear +dogmatize +dole +dolly +dome +domesticize +domicile +dominate +domineer +don +donate +dong +doodle +doom +dope +dose +doss +dot +dote +double +double-bank +double-declutch +double-fault +double-stop +double-time +doublebogey +doublecheck +doublecross +doublepark +doublespace +doubletongue +doubt +douche +douse +dovetail +dow +dower +down +downgrade +downplay +dowse +doze +drab +drabble +draft +draft +draggle +draghunt +dragoon +drain +dramatize +drape +drat +draw +drawl +dread +dream +dredge +dree +drench +dress +dribble +drift +drill +drink +drip +drive +drivel +drizzle +drone +drool +droop +drop +dropkick +dropout +drown +drowse +drub +drudge +drug +drum +dry +dry-salt +dryclean +drydock +dub +duck +duel +duff +dulcify +dull +dumfound +dummy +dump +dun +dung +dunk +dunt +dup +dupe +duplicate +dusk +dust +dwarf +dwell +dwindle +dye +dyke +dynamite +ear +earbash +earmark +earn +earth +earwig +ease +eat +eavesdrop +ebb +ebonize +echelon +echo +eclipse +economize +eddy +edge +edify +edit +editorialize +educate +educe +edulcorate +eff +efface +effect +effectuate +effervesce +effloresce +effuse +egest +egg +egotrip +egress +ejaculate +eject +eke +elaborate +elapse +elasticate +elasticize +elate +elbow +elect +electioneer +electrify +electrocute +electrodeposit +electroform +electrolyze +electroplate +electrotype +elegize +elevate +elicit +elide +eliminate +eloin +elongate +elope +elucidate +elude +elute +elutriate +emaciate +emanate +emancipate +emasculate +embalm +embank +embargo +embark +embarrass +embattle +embay +embellish +embezzle +embitter +emblaze +emblazon +emblemize +embody +embolden +embosom +emboss +embow +embowel +embower +embrace +embrangle +embrocate +embroider +embroil +embus +emend +emerge +emigrate +emit +emote +emotionalize +empathize +emphasize +emplace +emplane +employ +empoison +empower +empt +empty +emulate +emulsify +enable +enact +enamel +enamour +encage +encamp +encarnalize +encash +enchain +enchant +enchase +encipher +encircle +enclasp +encode +encompass +encore +encounter +encourage +encroach +encrypt +encyst +end +endamage +endanger +endear +endeavour +endow +endure +energize +enervate +enface +enfeeble +enfeoff +enfilade +enforce +enfranchise +engage +engender +engineer +english +englut +engorge +engrail +engrave +engross +enhance +enigmatize +enisle +enjoin +enjoy +enkindle +enlace +enlarge +enlighten +enlist +enliven +ennoble +enounce +enplane +enquire +enrage +enrapture +enrich +enrobe +enroll +enroot +ensanguine +ensconce +enshrinshrine +enshroud +ensile +enslave +ensue +enswathe +entail +entangle +enter +entertain +enthrall +enthrone +enthuse +entice +entitle +entoil +entomb +entomologize +entrain +entrammel +entrance +entrap +entwintwine +enucleate +enumerate +enunciate +envelop +envenom +environ +envisage +envision +envy +enwind +enwomb +enwrap +enwreath +epigrammatize +epilate +epitomize +equal +equalize +equate +equilibrate +equip +equipoise +equiponderate +equivocate +eradiate +eradicate +erase +erect +erode +err +eructate +erupt +escalade +escalate +escallop +escape +escarp +escheat +eschew +escort +escribe +espalier +espouse +espy +esquire +essay +establish +esteem +esterify +estimate +estivate +estop +estrange +estreat +etch +eternize +etherealize +etherify +etherize +ethicize +etiolate +etymologize +euchre +euhemerize +eulogize +euphemize +euphonize +europeanize +evacuate +evade +evaginate +evaluate +evanesce +evangelize +evanish +evaporate +even +eventuate +evert +evict +evidence +evince +eviscerate +evite +evoke +evolve +exacerbate +exact +exaggerate +exalt +examine +exasperate +excavate +exceed +excel +except +excerpt +exchange +excide +excise +excite +exclaim +exclude +excogitate +excommunicate +excorciate +excoriate +excrete +excruciate +exculpate +excuse +execrate +execute +exemplify +exempt +exenterate +exercise +exert +exfoliate +exhale +exhaust +exhibit +exhilarate +exhort +exhume +exile +exist +exit +exonerate +exorcize +expand +expatiate +expatriate +expect +expectorate +expedite +expel +expend +expense +experience +experiment +experimentalize +expertize +expiate +expire +explain +explant +explicate +explode +exploit +explore +export +expose +expostulate +expound +express +expropriate +expunge +expurgate +exsanguinate +exscind +exsect +exsert +exsiccate +extemporize +extend +extenuate +exterminate +externalize +extinguish +extirpate +extoll +extort +extract +extradite +extrapolate +extravagate +extravasate +extricate +extrude +exuberate +exude +exult +exuviate +eye +eyeball +eyelet +f^ete +fable +fabricate +face +faceharden +faceoff +facet +facilitate +factor +factorize +fade +fadge +faff +fag +fail +faint +fair +fake +fall +fallow +false-card +falsify +falter +fame +familiarize +famish +fan +fanaticize +fancy +fankle +fantasize +faradize +farce +fare +farm +farrow +fart +fascinate +fash +fashion +fast +fasten +fat +fate +father +fathom +fatigue +fatten +fault +favour +fawn +fay +faze +fear +feast +feather +featherbed +featherstitch +feature +feaze +fecundate +fed +federalize +federate +feed +feel +feeze +feign +feint +felicitate +fellow +feminize +fence +fend +feoff +ferment +ferret +ferrule +ferry +fertilize +ferule +fester +festoon +fetch +fete +fetter +fettle +feud +feudalize +fever +fib +fictionalize +fiddle +fiddlefaddle +fidge +fidget +field +fife +fig +fight +figure +filagree +filch +file +filiate +filibuster +fill +fillagree +fillagree +fillet +fillip +film +filmset +filter +filtrate +fin +finagle +finalize +finance +find +fine +fine-draw +finesse +finger +fingerprint +finish +fink +fire +firecure +fireproof +firm +first-foot +fishes +fishtail +fissure +fist +fit +fix +fixate +fizz +fizzle +flabbergast +flag +flagellate +flail +flake +flam +flame +flameout +flange +flank +flannel +flap +flare +flash +flatten +flatter +flatter +flaunt +flavour +flaw +fleck +fledge +flee +fleece +fleer +fleet +flense +flesh +fletch +flex +fley +flick +flicker +flight +flimflam +flinch +fling +flint +flip +flirt +flit +flitch +flite +flitter +float +flocculate +flock +flog +flood +floodlight +floor +flop +flounce +flounder +flour +flourish +flout +flow +flower +fluctuate +flue-cure +fluff +fluidize +fluke +flume +flummox +flunk +fluoresce +fluoridate +fluoridize +fluorinate +flurry +flush +fluster +flute +flutter +flux +fly +flyblow +flyfish +flyspeck +flyte +foal +foam +fob +focalize +focus +fodder +fog +foil +foin +foist +fold +foliate +folio +folk +folk-dance +follow +foment +fondle +fool +foot +foot-slog +footle +footnote +foozle +forage +foray +forbear +forbid +force +force-land +force-ripe +forcefeed +ford +forearm +forebode +forecast +foreclose +foredo +foredoom +foregather +forehand +foreknow +forelock +foreordain +forereach +forerun +foresee +foreshadow +foreshorten +foreshow +forespeak +forest +forest +forestall +foreswear +foretaste +foretell +foretoken +forewarn +forfeit +forfend +forgat +forgather +forge +forget +forgive +forgo +forjudge +fork +form +formalize +format +formicate +formularize +formulate +fornicate +forsake +forspeak +forswear +fortify +fortress +fortune +forward +fossick +fossilize +foster +foul +founder +founder +fourflush +fowl +fox +foxhunt +fraction +fractionate +fractionize +fracture +frag +fragment +frame +franchise +frank +frap +fraternize +fray +frazzle +freak +freckle +free +free-select +free-wheel +freeboot +freelance +freeload +freewheel +freeze +freezedry +freight +french-polish +frenchify +frenzy +frequent +fresh +freshen +fret +fribble +fricassee +friend +frig +frighten +frill +fringe +frisk +fritt +fritter +frivol +frizz +frizzle +frock +frog +frogmarch +frolic +front +frost +froth +frown +fructify +fruit +frustrate +fry +fuck +fuddle +fudge +fuel +fulfill +fulgurate +fuller +fuller +fulminate +fumble +fume +fumigate +fun +function +fund +funk +funnel +fur +furbelow +furbish +furcate +furl +furlough +furnish +furrow +further +fusillade +fuss +fustigate +fuze +fuzz +gab +gabble +gad +gaff +gag +gaggle +gain +gainsay +gall +gallant +gallicize +gallivant +gallop +galumph +galvanize +gam +gamble +gambol +game +gammon +gang +gangrene +gape +garage +garb +garble +garden +gargle +garland +garment +garner +garnish +garnishee +garrison +garrotte +garter +gas +gasconade +gash +gasify +gasp +gat +gate +gate-crash +gatecrash +gather +gauge +gawk +gawp +gaze +gazette +gazump +gear +gee +gelatinize +geld +gem +geminate +gemmate +generalize +generate +gentle +genuflect +geocode +geologize +geometrize +germanize +germinate +gerrymander +gestate +gesticulate +gesture +get +getter +ghost +ghostwrite +gib +gibber +gibbet +gibe +gie +gift +giftwrap +gig +giggle +gild +gill +gimlet +gimme +gin +ginger +gird +girdle +girth +give +glac_e +glaciate +glad +gladden +glair +glamourize +glance +glare +glass +glaze +gleam +glean +glide +glimmer +glimpse +glint +glissade +glisten +glister +glitter +gloat +globe +globe-trot +gloom +glorify +glory +gloss +glove +glow +glower +gloze +glue +glut +gnarl +gnash +gnaw +gnosticize +go +goad +gob +gobble +goffer +goggle +gold-plate +gollop +golly +goof +goose +goosestep +gore +gorge +gormandize +gossip +goster +gothicize +gotta +gouge +govern +gown +grab +grabble +grace +gradate +grade +graduate +graft +grain +grandstand +grangerize +grant +granulate +graph +graphitize +grapple +grasp +grass +grate +gratify +gratulate +grave +gravel +gravitate +graze +grease +greaten +grecize +gree +greet +grey +griddle +gride +grieve +grill +grimace +grime +grin +grind +grip +gripe +grit +grizzle +groan +groin +groom +groove +grope +gross +grouch +ground +group +grouse +grout +grovel +grow +growl +grub +grubstake +grudge +grumble +grump +grunt +guarantee +guaranty +guard +gudgeon +guerdon +guess +guest +guffaw +guide +guillotine +guise +gulf +gull +gully +gulp +gum +gumshoe +gun +gurgle +gush +gusset +gut +gutter +gutturalize +guy +guzzle +gybe +gyp +gyrate +gyve +habilitate +habit +habituate +hachure +hack +hackle +hackney +hacksaw +hade +haft +haggle +hail +hale +half-volley +hallal +hallmark +halloo +hallow +hallucinate +halo +halogenate +halter +halter +halve +ham +hammer +hamper +hamshackle +hamstring +hand +hand-knit +handcuff +handfast +handfeed +handicap +handle +handpick +hang +hank +hanker +hansel +hap +happen +harangue +harass +harbinger +harbour +harden +hare +hark +harm +harmonize +harness +harp +harpoon +harrow +harrumph +harry +harvest +hash +hasp +hassle +haste +hasten +hat +hatch +hatchel +hate +haul +haunt +have +haven +haver +havoc +haw +hawk +hawse +hay +hazard +haze +head +head-load +headline +headreach +heal +heap +hear +hearken +heart +hearten +heat +heathenize +heattreat +heave +hebetate +hebraize +heckle +hector +hedge +hedge-hop +hedgehop +heed +heel +heel-and-toe +heft +heighten +heist +hellenize +helm +help +helve +hem +hemagglutinate +hemorrhage +hemstitch +henpeck +hent +herald +herd +heroworship +herringbone +hesitate +heterodyne +hew +hex +hibernate +hiccough +hiccup +hide +hie +higgle +highhat +highlight +hight +hightail +hijack +hike +hill +hilt +hinder +hinge +hinny +hint +hire +hispanicize +hiss +hit +hitch +hitchhike +hive +hoard +hoarsen +hoax +hob +hobble +hobbyhorse +hobnob +hock +hocus +hocuspocus +hoe +hog +hogtie +hoick +hoiden +hoist +hoke +hold +holden +hole +holiday +holler +hollow +holp +holpen +holystone +homage +home +homogenize +homologate +homologize +hone +honey +honeycomb +honeymoon +honor +honour +hood +hoodoo +hoodwink +hoof +hook +hookup +hoop +hooray +hoot +hoover +hop +hope +hopple +horde +horn +hornswoggle +horrify +horse +horseshoe +horsewhip +hose +hospitalize +host +hot-press +hotdog +hotfoot +hound +house +house-train +housel +hovel +hover +howl +huckster +huddle +huff +hug +huggermugger +hulk +hum +humanize +humble +humbug +humidify +humiliate +humour +hump +hunch +hunger +hunt +hurdle +hurl +hurrah +hurry +hurt +hurtle +husband +hush +hustle +hutch +huzzah +hybridize +hydrate +hydrogenize +hydrolyze +hydroplane +hymn +hyperbolize +hypersensitize +hypertrophy +hyphenate +hypnotize +hyposensitize +hypostasize +hypostatize +hypothecate +hypothesize +hysterectomize +ice +iceskate +idealize +ideate +identify +idle +idolatrize +idolize +ignite +ignore +illegalize +illtreat +illude +illume +illuminate +illumine +illuse +illustrate +image +imagine +imbed +imbibe +imbricate +imbrue +imbue +imitate +immaterialize +immerge +immerse +immigrate +immingle +immix +immobilize +immolate +immortalize +immunize +immure +imp +impact +impair +impale +impanel +imparadise +impart +impassion +impaste +impeach +impearl +impede +impel +impend +imperil +impersonalize +impersonate +impetrate +impinge +implant +implead +implement +implicate +implode +implore +imply +impolder +import +importune +impose +impost +impound +impoverish +impower +imprecate +impregnate +impress +imprint +imprison +impropriate +improve +improvise +impugn +impulse-buy +impute +inactivate +inarch +inaugurate +inbreathe +inbred +incandesce +incapacitate +incapsulate +incarcerate +incardinate +incarnadine +incarnate +incase +incense +incept +incinerate +incise +incite +incline +inclose +include +incommode +inconvenience +incorporate +incrassate +increase +incriminate +incross +incrust +incubate +inculcate +inculpate +incumber +incur +incurvate +indemnify +indent +indenture +index +indicate +indict +indispose +indite +individualize +individuate +indoctrinate +indorse +induce +induct +indue +indulge +indurate +industrialize +indwell +inearth +inebriate +infamize +infatuate +infect +infer +infest +infibulate +infiltrate +infix +inflame +inflate +inflect +inflict +influence +infold +inform +infract +infringe +infuriate +infuse +ingather +ingeminate +ingenerate +ingest +ingot +ingraft +ingrain +ingratiate +ingulf +ingurgitate +inhabit +inhale +inhere +inherit +inhibit +inhume +initial +initialize +initiate +inject +injure +ink +inlace +inlay +inlet +inmesh +innervate +innerve +innovate +inoculate +inosculate +inquire +insalivate +inscribe +inseminate +insert +inset +inshrine +insinuate +insist +insnare +insolate +insoul +inspan +inspect +insphere +inspire +inspirit +inspissate +install +instance +instantiate +instate +instigate +instill +institute +institutionalize +instruct +insufflate +insulate +insult +insure +integrate +intellectualize +intend +intenerate +intensify +inter +interact +interbreed +intercalate +intercede +intercept +interchange +intercommunicate +intercrop +intercross +intercut +interdict +interdigitate +interest +interfere +interfile +interflow +interfuse +intergrade +interiorize +interject +interlace +interlaminate +interlap +interlard +interlay +interleave +interlineate +interlink +interlock +interlope +intermarry +intermingle +intermit +intermix +intern +internalize +internationalize +interosculate +interpage +interpellate +interpenetrate +interplead +interpolate +interpose +interpret +interrelate +interrogate +interrupt +intersect +interspace +intersperse +interstratify +intertwine +intervene +interview +interweave +intimate +intimidate +intitule +intonate +intone +intoxicate +intreat +intrench +intrigue +introduce +introject +intromit +introspect +introvert +intrude +intrust +intubate +intuit +intumesce +intussuscept +intwine +inundate +inure +inurn +invade +invaginate +invalid +invalidate +inveigh +inveigle +invent +inventory +invert +invest +investigate +invigilate +invigorate +invite +invocate +invoice +invoke +involute +involve +inweave +inwrap +iodate +iodize +ionize +irk +iron +ironize +irradiate +irrigate +irritate +irrupt +islamize +island +isochronize +isolate +isomerize +issue +italianize +italicize +itch +item +itemize +iterate +itinerate +jab +jabber +jack +jacket +jackknife +jackknife +jade +jaga +jagg +jail +jam +jampack +jangle +japan +jape +jar +jargon +jargonize +jaundice +jaunt +jaup +jaw +jay-walk +jaywalk +jazz +jeer +jell +jellify +jelly +jemmy +jeopardize +jerk +jerrybuild +jess +jest +jet +jettison +jew +jewel +jib +jibe +jig +jiggle +jilt +jimmy +jingle +jink +jinx +jitter +job +jockey +jog +jog-trot +joggle +join +joint +joist +joke +jollify +jolly +jolt +jook +josh +jot +jounce +journalize +journey +joust +joy +joy-ride +joypop +jubilate +judaize +judder +judge +jug +juggle +jugulate +jumble +jump +jumpstart +junk +junket +justify +justle +jut +juxtapose +kalsomine +kangaroo +kayo +keck +kedge +keek +keel +keelhaul +keen +keep +ken +kennel +kep +keratinize +kerfuffle +kerne +kernel +key +keyboard +keynote +keypunch +kibble +kibitz +kibosh +kick +kick-start +kid +kidnap +kill +kiln +kilt +kindle +kip +kipper +kiss +kite +kitten +kittle +knacker +knap +knead +kneel +knife +knight +knit +knob +knock +knoll +knot +know +knurl +ko +kockelsch +kotow +kowtow +kraal +kyanize +label +labialize +labour +lace +lacerate +lack +lackey +lacquer +lactate +ladder +lade +ladle +ladyfy +lag +laicize +laik +lair +lallygag +lam +lamb +lambaste +lame +lament +laminate +lampoon +lance +land +landscape +languish +lap +lapidate +lapidify +lapse +lard +largen +lark +larn +larrup +lase +lash +lasso +last +latch +lath +lathe +lather +latinize +lattice +laud +laugh +launch +launder +lave +lavish +layer +layer +laze +leach +lead +leaf +league +leak +lean +leap +leapfrog +learn +lease +leash +leather +leave +leaven +lecture +ledger +leer +leer +left +leg +legalize +legislate +legitimate +legitimize +leister +lend +lengthen +lessen +lesson +let +letch +letter +levant +level +lever +levigate +levitate +levy +lhlike +liaise +libel +liberalize +liberate +librate +licence +license +lick +lie +lift +ligate +ligature +light +lighten +lignify +like +liken +lilt +limb +limber +lime +limit +limn +limp +line +linger +link +lionize +lip +lipread +liquate +liquefy +liquesce +liquidate +liquidize +liquify +liquor +lisp +list +listen +lit +lithograph +litigate +litter +live +liven +lixiviate +load +loaf +loam +loan +loathe +lob +lobby +localize +locate +lock +loco +lodge +loft +log +logroll +loiter +loll +lollop +long +look +loom +loop +loophole +loose +loosen +loot +lop +lope +lord +lose +lot +louden +lounge +lour +lout +love +lower +lower +lowercase +lubricate +luck +lucubrate +luff +lug +lull +lullaby +lumber +luminesce +lump +lunch +lunge +lurch +lure +lurk +lush +lust +lustrate +lustre +lute +luxate +luxuriate +lynch +lyophilize +lyse +macadamize +mace +macerate +machicolate +machinate +machine +machinegun +maculate +mad +madden +maffick +magnetize +magnify +mail +maim +maintain +major +make +maladminister +maledict +malfunction +malign +malinger +malt +maltreat +mamaguy +mambo +mammock +man +man-handle +manacle +manage +mandate +manducate +maneuver +mangle +manhandle +manicure +manifest +manifold +manipulate +manoeuvre +mantle +manufacture +manumit +manure +map +mar +maraud +marble +marcel +march +margin +marginalize +marginate +marinade +marinate +mark +market +marl +maroon +marry +marshal +martyr +marvel +mash +mask +mason +masquerade +mass +massacre +massage +massproduce +mast +master +master-mind +mastermind +masticate +masturbate +mat +match +matchmark +mate +materialize +matriculate +matter +maturate +mature +maul +maunder +maximize +may +maze +mean +meander +measure +mechanize +medal +meddle +mediate +mediatize +medicate +meditate +meet +meld +meliorate +mellow +melodize +melodramatize +melt +memorialize +memorize +menace +mend +menstruate +mention +mercerize +merchant +mercurate +mercurialize +merge +merit +mesh +mesmerize +mess +metabolize +metal +metallize +metamorphose +metaphrase +metaphysicize +metastasize +metathesize +mete +meter +methodize +methought +methylate +metricate +metricize +metrify +mew +mewl +mezzotint +miaul +microfilm +micturate +middle +miff +might +migrate +mike +milden +mildew +militarize +militate +milk +mill +milt +mime +mimeograph +mimeograph +mimic +mince +mind +mine +mineralize +mingle +miniaturize +minify +minimize +minister +mint +minute +mire +mirror +misadvise +misapply +misapprehend +misappropriate +misbecome +misbehave +miscalculate +miscall +miscarry +miscast +misconceive +misconduct +misconstrue +miscount +miscreate +miscue +misdate +misdeal +misdemean +misdirect +misdoubt +misfile +misfire +misfit +misgive +misgovern +misguide +mishandle +mishear +mishit +misinform +misinterpret +misjudge +mislay +mislead +mislike +mismanage +mismatch +misname +misplace +misplay +mispled +misprint +misprize +mispronounce +misquote +misread +misreport +misrepresent +misrule +miss +misshape +mission +misspell +misspend +misstate +mist +mistake +mister +mistime +mistranslate +mistreat +mistrust +misunderstand +misuse +mitch +mitigate +mitre +mix +mizzle +moan +moat +mob +mobilize +mock +model +moderate +modernize +modge +modify +modulate +mohammedanize +moil +moisten +moisturize +moither +molest +mollify +mollycoddle +molt +monetize +mongrelize +monitor +monopolize +monotonize +moo +mooch +moon +moonlight +moor +moot +mop +mope +moralize +mordant +mortar +mortgage +mortify +mortise +mosey +mothball +mother +mothproof +mothproof +motion +motivate +motive +motor +motorize +mottle +mould +moulder +moult +mound +mount +mountaineer +mountebank +mourn +mouse +mouth +move +mow +muck +muckamuck +muckrake +mud +muddle +muddy +muff +muffle +mug +mulch +mulct +mull +multiply +mumble +mumm +mummify +mump +munch +municipalize +munition +murdabad +murder +mure +murmur +murther +muscle +muse +mushroom +muss +must +muster +mutate +mutch +mute +mutilate +mutiny +mutter +mutualize +muzz +muzzle +mystify +mythicize +mythologize +nab +nag +nail +name +name-drop +nap +napalm +narcotize +nark +narrate +narrow +nasalize +nationalize +natter +naturalize +nauseate +navigate +naysay +nazify +near +neaten +nebulize +necessitate +neck +necrose +need +needle +negate +neglect +negotiate +neigh +neighbour +neologize +nerve +nest +nestle +net +nettle +network +neuter +neutralize +nibble +nick +nickel +nicker +nickname +nictitate +nid-nod +nidify +niello +niggle +nigrify +nip +nitrify +nitrogenize +nix +nobble +nock +nod +noddle +noise +nomadize +nominate +nonplus +nonpros +nonsuit +normalize +normanize +nose +nosedive +nosh +notarize +notate +notch +note +notice +notify +nourish +novelize +nucleate +nudge +nullify +number +number +numerate +nurse +nurture +nut +nuzzle +oar +obelize +obey +obfuscate +object +objectify +objurgate +obligate +oblige +oblique +obliterate +obnubilate +obscure +obsecrate +observe +obsess +obsolesce +obsolete +obstruct +obtain +obtest +obtrude +obtund +obturate +obvert +obviate +occasion +occidentalize +occlude +occult +occupy +occur +ochre +octuple +offend +offer +officer +officiate +offload +offprint +offset +ogle +oil +ok +okay +old-talk +omen +omit +ooze +opalesce +opaque +ope +open +operate +operatize +opiate +opine +oppilate +oppose +oppress +oppugn +opsonize +opt +optimize +orate +orb +orbit +orchestrate +ordain +order +organize +orient +orientalize +orientate +originate +ornament +orphan +oscillate +osculate +osmose +ossify +ostracize +ought +oust +out +out-herod +outbalance +outbid +outbrave +outbreed +outclass +outcrop +outcross +outcry +outdate +outdistance +outdo +outface +outfight +outfit +outflank +outfoot +outfox +outgain +outgas +outgeneral +outgo +outgrow +outgun +outjockey +outlast +outlaw +outlay +outleap +outline +outlive +outman +outmanoeuvre +outmarch +outmatch +outnumber +outpace +outperform +outplay +outpoint +outpour +outrage +outrange +outrank +outreach +outride +outrival +outrun +outsail +outsell +outshine +outshoot +outsmart +outspan +outspread +outstand +outstay +outstretch +outstrip +outthink +outvie +outvote +outwear +outweigh +outwit +outwork +over-burden +over-estimate +over-expose +over-heat +over-simplify +overachieve +overact +overarch +overawe +overbalance +overbear +overbid +overblow +overbuild +overburden +overcall +overcapitalize +overcharge +overcloud +overcome +overcompensate +overcook +overcrop +overcrowd +overdevelop +overdo +overdose +overdraw +overdress +overdrive +overdye +overeat +overemphasize +overestimate +overexert +overexpose +overfeed +overflow +overfly +overgrow +overhand +overhang +overhaul +overhear +overheat +overindulge +overissue +overjoy +overland +overlap +overlay +overleap +overlie +overlive +overload +overlook +overman +overmaster +overmatch +overpass +overpay +overpersuade +overpitch +overplay +overpower +overpraise +overprint +overproduce +overprotect +overrate +overreach +overreact +overrefine +override +overrule +overrun +overscore +oversee +oversell +overset +oversew +overshadow +overshoot +overshot +oversimplify +oversleep +overspend +overspill +overstaff +overstate +overstay +oversteer +overstep +overstock +overstrain +overstuff +oversubscribe +overtake +overtask +overtax +overthrow +overtime +overtop +overtrade +overtrump +overture +overturn +overvalue +overwatch +overweigh +overweight +overwhelm +overwind +overwinter +overwork +overwrite +oviposit +ovulate +owe +own +oxidate +oxidize +oxygenize +oyster +ozonize +pace +pacify +pack +package +packet +pad +paddle +padlock +paganize +page +paginate +pain +paint +pair +pal +palatalize +palaver +pale +palisade +palliate +palm +palpate +palpebrate +palpitate +palter +pamper +pamphleteer +pan +pander +pandy +panegyrize +panel +panhandle +panic +pant +pantomime +paper +parabolize +parachute +parade +paragon +paragraph +parallel +paralyze +paraphrase +parasitize +parboil +parbuckle +parcel +parch +pardon +pare +parenthesize +park +parlay +parley +parleyvoo +parody +parole +parrot +parry +parse +part +partake +participate +particularize +partition +partner +pash +pass +passage +past +paste +pasteurize +pasture +pat +patch +patent +patrol +patronize +patter +pauperize +pause +pave +pavilion +paw +pawn +pay +peace +peach +peacock +peak +peal +pearl +pebble +peck +pectize +peculate +pedal +peddle +pedestrianize +pee +peek +peel +peen +peep +peer +peeve +peg +pellet +pelt +pen +penalize +penance +pencil +pend +penetrate +peninsulate +pension +people +pep +pepper +pepsinate +peptize +peptonize +perambulate +perceive +perch +percolate +percuss +peregrinate +perennate +perfect +perforate +perform +perfume +perfuse +perish +perjure +perk +permeate +permit +permute +perorate +peroxide +perpend +perpetrate +perpetuate +perplex +persecute +persevere +persist +personalize +personate +personify +perspire +persuade +pertain +perturb +peruse +pervade +pervert +pester +pestle +pet +peter +petition +petrify +pettifog +phantasy +phase +phenolate +philander +philosophize +phlebotomize +phonate +phone +phosphatize +phosphorate +phosphoresce +photocompose +photocopy +photoengrave +photograph +photolithograph +photomap +photosensitize +photoset +photostat +photostat +photosynthesize +phototype +phrase +physic +pi +pick +pickaxe +picket +pickle +picnic +picture +piddle +piece +pierce +piffle +pig +pigeonhole +pigstick +pike +pile +pilfer +pilgrimage +pill +pillage +pillar +pillory +pillow +pilot +pimp +pin +pinch +pinchhit +pine +pinfold +ping +pinion +pink +pinnacle +pinpoint +pinpoint +pinprick +pioneer +pip +pipe +pipeline +pipette +pique +pirate +pirouette +pish +piss +pistol +pistolwhip +pit +pitapat +pitch +pitchfork +pith +pitterpatter +pity +pivot +pize +placard +placate +place +placekick +plagiarize +plague +plain +plait +plan +plane +plane-table +planish +plank +plant +plash +plasmolyze +plaster +plasticize +plate +platemark +platinize +platitudinize +platonize +play +playact +playback +pleach +plead +please +pleasure +pleat +pledge +plenish +plight +ploat +plod +plodge +plonk +plop +plot +plough +plow +pluck +plug +plumb +plume +plummet +plump +plunder +plunge +plunk +pluralize +ply +poach +pocket +pockmark +pod +podzolize +poetize +poind +point +poise +poison +poke +polarize +pole +poleax +poleaxe +polevault +police +polish +politicize +politick +polka +poll +pollard +pollinate +pollute +polymerize +pomade +pommel +ponce +ponder +pong +poniard +pontificate +poohpooh +pool +poop +pop +popple +popularize +populate +pore +port +portage +portend +portion +portray +pose +posit +position +poss +posse +possess +post +postdate +postfix +postil +postpone +postulate +posture +posturize +pot +potentiate +pother +potter +pouch +poultice +pounce +pound +pour +poussette +pout +powder +power +powerdive +powwow +practice +practise +praise +prance +prank +prate +prattle +pray +pre-digest +preach +preachify +prearrange +precancel +precast +precede +precess +precipitate +precis +preclude +preconceive +precondition +preconize +precontract +predate +predecease +predestinate +predestine +predetermine +predicate +predict +predigest +predispose +predominate +preempt +preen +preexist +prefabricate +preface +prefer +prefigure +prefix +prejudge +prejudice +prelect +prelude +premeditate +premier +premise +premiss +premonish +preoccupy +preordain +prepare +prepay +preponderate +prepossess +prerecord +preregister +presage +prescind +prescribe +present +preserve +preside +presignify +press +pressgang +pressure +pressure-cook +pressurize +prestress +presume +presuppose +pretend +pretermit +prettify +prevail +prevaricate +prevent +previse +prevue +prey +price +prick +prickle +pride +prig +prill +prime +primp +prink +print +prise +privateer +privatize +privilege +prize +probe +proceed +process +procession +proclaim +procrastinate +procreate +procure +prod +produce +profane +profess +proffer +profit +profiteer +prog +prognosticate +programme +programtrade +progress +prohibit +project +prolapse +proliferate +prologue +prolong +promenade +promise +promote +prompt +promulgate +pronate +prong +pronominalize +pronounce +proof +proofread +proofread +prop +propagandize +propagate +propel +propend +prophesy +propitiate +proportion +proportionate +propose +proposition +propound +prorate +prorogue +proscribe +prose +prosecute +proselyte +proselytize +prospect +prosper +prostitute +prostrate +protect +protest +protract +protrude +protuberate +prove +provide +provision +provoke +prowl +prune +prussianize +pry +psyche +psycho-analyse +psychoanalyze +psychologize +pubcrawl +publicize +publish +pucker +puddle +puff +pug +puke +pule +pull +pullulate +pulp +pulsate +pulse +pulverize +pummel +pump +pun +punce +punch +punctuate +puncture +punish +punt +pup +pupate +pur_ee +purchase +purfle +purge +purify +purl +purloin +purport +purpose +purr +purse +pursue +purvey +push +push-start +pussyfoot +pustulate +put +putput +putrefy +putt +putter +putty +puzzle +pyramid +quack +quadrisect +quadruple +quadruplicate +quaff +quail +quake +qualify +quant +quantify +quantize +quarantine +quarrel +quarry +quarter +quartersaw +quash +quaver +queen +queer +quell +quench +query +quest +question +queue +quibble +quicken +quickfreeze +quickstep +quiet +quieten +quill +quilt +quintuple +quintuplicate +quip +quit +quitclaim +quiver +quiz +quote +rabbit +rabble +race +racemize +racketeer +rackrent +racquet +raddle +radiate +radio +radioactivate +radiotelegraph +radiotelephone +raffle +raft +rag +rage +ragout +raid +rail +railroad +rain +rainproof +raise +rake +rally +ram +ramble +ramify +ramp +rampage +rampart +ranch +randomize +range +rank +rankle +ransack +ransom +rant +rap +rape +rappel +rapture +rarify +rash +rasp +rat +rate +ratify +ratiocinate +ration +rationalize +rattle +rattoon +rattoon +ravage +rave +ravel +ravin +ravish +ray +raze +razor-cut +razz +re-act +re-afforest +re-cede +re-count +re-cover +re-create +re-dress +re-echo +re-form +re-fund +re-join +re-present +re-press +re-proof +re-serve +re-sign +re-sort +re-sound +re-trace +re-tread +reach +react +reactivate +read +readdress +readjust +ready +reaffirm +realign +realize +ream +reanimate +reap +reappear +reapportion +reappraise +rear +reard +rearm +rearrange +reason +reassert +reassign +reassure +reave +rebate +rebel +rebellow +rebound +rebound +rebuff +rebuild +rebuke +rebut +recalculate +recalesce +recall +recant +recap +recapitulate +recapture +recast +recce +recede +receipt +receive +recentralize +recess +reciprocate +recite +reck +reckon +reclaim +reclassify +recline +recognize +recoil +recollect +recommend +recommit +recompense +recompose +reconcile +recondition +reconnect +reconnoitre +reconsider +reconstitute +reconstruct +reconvert +record +recount +recoup +recover +recreate +recriminate +recrudesce +recruit +recrystallize +rectify +recuperate +recur +recurve +recycle +red +redact +redd +redden +reddle +rede +redeem +redeploy +redesign +redevelop +redintegrate +redirect +redistribute +redo +redouble +redound +redpencil +redraft +redraw +redress +reduce +reduplicate +reed +reef +reek +reel +reelect +reemphasize +reenact +reenter +reest +reestablish +reeve +reexamine +reexport +reface +refer +referee +reference +refile +refill +refinance +refine +refit +reflate +reflect +refloat +reflux +refocuse +reforest +reform +refract +refrain +refresh +refrigerate +reft +refuel +refuge +refund +refurbish +refuse +refute +regain +regale +regard +regelate +regenerate +regiment +register +regorge +regrate +regress +regret +regroup +regularize +regulate +regurgitate +rehabilitate +rehash +rehear +rehearse +reheat +rehouse +reify +reign +reignite +reimburse +reimport +rein +reincarnate +reindict +reinforce +reinstate +reinstitute +reinsure +reintroduce +reinvent +reinvest +reinvigorate +reissue +reiterate +reive +reject +rejig +rejoice +rejoin +rejuvenate +rejuvenesce +rekindle +relapse +relate +relativize +relaunch +relax +relay +release +relegate +relent +relieve +reline +relinquish +relish +relive +relocate +reluct +relumine +rely +remain +remainder +remake +remand +remark +remarry +rematch +remedy +remember +remilitarize +remind +reminisce +remise +remit +remodel +remonetize +remonstrate +remould +remount +remove +remunerate +rename +rencounter +rend +render +rendezvous +renegotiate +renegue +renew +renounce +renovate +rent +reopen +reorganize +reorient +reorientate +repackage +repair +repartition +repast +repatriate +repay +repeal +repeat +repel +repent +rephrase +repine +replace +replay +replenish +replevin +replevy +replicate +reply +repoint +repone +report +repose +reposit +reposition +repossess +repot +reprehend +represent +repress +reprieve +reprimand +reprint +reprise +reproach +reprobate +reproduce +reprove +republicanize +repudiate +repugn +repulse +repurchase +repute +request +require +requisition +requite +reread +reroute +rerun +reschedule +rescind +rescue +research +reseat +resell +resemble +resent +reserve +reset +resettle +reshape +reshuffle +reside +resign +resile +resin +resinate +resist +resit +resole +resolve +resonate +resorb +resort +resound +respect +respire +respite +respond +rest +restate +restock +restore +restrain +restrict +restring +restructure +resubmit +result +resume +resurface +resurge +resurrect +resuscitate +ret +retail +retain +retake +retaliate +retard +retch +retell +rethink +reticulate +retire +retool +retort +retouch +retrace +retract +retread +retreat +retrench +retrieve +retroact +retrocede +retrofit +retrograde +retrogress +retroject +retrospect +retry +return +reunify +reunite +rev +revalorize +revalue +revamp +reveal +revegetate +revel +revenge +reverberate +revere +reverence +reverse +revert +revest +revet +review +revile +revise +revisit +revitalize +revive +revivify +revoice +revoke +revolt +revolutionize +revolve +reward +rewind +rewire +reword +rework +rewrite +rhapsodize +rhubarb +rib +ribbon +rice +rick +ricochet +rid +riddle +ride +ridge +ridicule +riff +riffle +rifle +rift +rig +right +righten +rigidify +rile +rim +rime +ring +rinse +riot +rip +ripen +riposte +ripple +rise +risk +ritualize +rival +rive +rivet +roam +roar +roast +rob +robe +rock +rock-and-roll +rocket +rodomontade +roil +roister +roll +rollerskate +rollick +romance +romanize +romanticize +romp +rone +roneo +rontgenize +roof +rook +roose +roost +root +rootle +roquet +rosin +roster +rot +rotate +rouge +rough +rough-house +roughcast +roughcast +roughdry +roughen +roughhew +roughhouse +round +roup +rouse +roust +rout +route +row +rowel +rub +rubber +rubberize +rubberneck +rubberneck +rubberstamp +rubbish +rubefy +rubricate +ruck +ruddle +rue +ruff +ruffle +ruggedize +ruin +rule +rumble +ruminate +rummage +rumour +rumple +run +rupture +ruralize +rush +russianize +rust +rusticate +rustle +rut +saber +sabotage +saccharize +sack +sacrifice +sadden +saddle +safeconduct +safeguard +safety +sag +sail +sain +saint +salify +salivate +sallow +sally +salt +salute +salvage +salve +samba +sample +sanctify +sanction +sand +sand-blast +sandbag +sandblast +sandcast +sandpaper +sandwich +sanforize +sanitize +sap +saponify +sash +sass +sate +satiate +satirize +satisfy +saturate +sauce +saunter +saut_e +savage +save +savour +savvy +saw +say +scab +scabble +scaffold +scag +scald +scale +scallop +scalp +scamp +scamper +scan +scandal +scandalize +scant +scape +scar +scare +scarf +scarify +scarp +scarper +scat +scathe +scatter +scavenge +scend +scent +sceptre +schedule +schematize +scheme +schlep +schmooze +school +schuss +scintillate +scissor +sclaff +scoff +scold +scollop +sconce +scoop +scoot +scorch +score +scorify +scorn +scotch +scour +scourge +scout +scowl +scrabble +scrag +scram +scramb +scramble +scrap +scrape +scratch +scrawl +screak +scream +screech +screen +screw +scribble +scribe +scrimmage +scrimp +scrimshank +scrimshaw +script +scroll +scroop +scrouge +scrounge +scrub +scrum +scrummage +scrump +scrunch +scruple +scrutinize +scry +scud +scuff +scuffle +scull +sculpt +sculpture +scum +scumble +scunge +scunner +scupper +scurry +scutch +scutter +scuttle +scythe +seal +seam +search +season +seat +secede +secern +seclude +second +secondguess +secrete +sectarianize +section +sectionalize +secularize +secure +sedate +seduce +see +seed +seek +seel +seem +seep +seesaw +seethe +segment +segregate +seine +seise +seize +select +sell +semaphore +send +sendoff +sense +sensitize +sentence +sentimentalize +sentinel +separate +septuple +sepulchre +sequester +sequestrate +sere +serenade +serialize +sermonize +serrate +serve +service +set +settle +sever +sew +sewer +sex +sextuplicate +shackle +shade +shadow +shadowbox +shaft +shag +shake +shall +shallow +shalt +sham +shamble +shame +shampoo +shanghai +shank +shape +share +sharecrop +shark +sharp +sharpen +shatter +shave +sheaf +shear +sheath +sheathe +sheave +shed +sheen +sheer +sheet +shell +shellac +shelter +shelve +shend +shepherd +sherardize +shew +shield +shift +shikar +shillyshally +shillyshally +shim +shimmer +shimmy +shin +shine +shingle +shinty +ship +shipwreck +shire +shirk +shirr +shit +shiver +shoal +shock +shoe +shoo +shoogle +shoot +shop +shop-lift +shore +short +short-list +shortchange +shortcircuit +shorten +shot +shotgun +should +shoulder +shouldst +shout +shove +shovel +show +showcase +showd +shower +shrank +shred +shriek +shrill +shrimp +shrine +shrink +shrinkwrap +shrive +shrivel +shroff +shroud +shrug +shrunk +shuck +shudder +shuffle +shun +shunt +shush +shut +shutter +shuttle +shy +sibilate +sic +sicken +side +side-dress +sideline +sideslip +sideslip +sidestep +sideswipe +sidetrack +sidetrack +sidle +siege +sieve +sift +sigh +sight +sightread +sightsee +sign +signal +signalize +signet +signify +signpost +sile +silence +silhouette +silicify +silk +silver +silver-plate +simmer +simper +simplify +simulate +simulcast +sin +sing +singe +single +single-step +single-tongue +singlefoot +singlespace +singularize +sink +sinter +sip +sire +sit +site +situate +siwash +size +sizzle +sjambok +skate +skedaddle +skeletonize +skelly +skelp +sken +sket +sketch +skewer +skewer +ski +ski-jump +skid +skim +skimp +skin +skinnydip +skinpop +skip +skipper +skirl +skirmish +skirr +skirt +skite +skitter +skive +skivvy +skulk +skunks +sky +sky-rocket +skydive +skyjack +skylark +skyrocket +slab +slack +slacken +slake +slalom +slam +slander +slang +slant +slap +slash +slat +slate +slaughter +slave +slaver +slay +sleave +sledge +sledgehammer +sleek +sleep +sleepwalk +sleet +sleeve +sleigh +slenderize +sleuth +slice +slick +slide +slight +slim +slime +sling +slink +slip +slipper +slipsheet +slit +slither +sliver +slobber +slog +sloganeer +slop +slope +slosh +slot +slouch +slough +slow +slue +sluff +slug +sluice +slum +slumber +slump +slur +slurp +slush +smack +smarm +smart +smarten +smash +smatter +smear +smell +smelt +smile +smirch +smirk +smite +smock +smoke +smooch +smoodge +smooth +smoothen +smote +smother +smoulder +smudge +smuggle +smut +smutch +snack +snaffle +snafu +snake +snap +snare +snarl +snatch +sneak +sneck +sned +sneer +sneeze +snick +snicker +sniff +sniffle +snigger +sniggle +snip +snipe +snitch +snivel +snog +snood +snooker +snoop +snooze +snore +snorkel +snort +snow +snowshoe +snub +snuff +snuffle +snug +snuggle +soak +soap +soar +sob +sober +socialize +sock +socket +sodden +soft-solder +soften +softland +softpedal +softsoap +soil +sojourn +solace +solarize +solder +soldier +sole +solemnify +solemnize +solfa +solicit +solidify +soliloquize +solo +solubilize +solvate +solve +somnambulate +sonnet +soot +soothe +soothsay +sop +sophisticate +sorn +sorrow +sort +sortie +sough +sound +soundproof +sour +souse +sovietize +sow +space +spacewalk +spade +spae +spag +spall +span +spancel +spangle +spank +spar +spare +sparge +spark +sparkle +spatter +spawn +spay +speak +spear +spearhead +specialize +specify +speckle +speculate +speechify +speed +spell +spellbind +spelunk +spend +spew +spice +spiel +spiflicate +spike +spile +spill +spin +spin-dry +spindle +spiral +spire +spiritualize +spit +spite +splash +splatter +splay +splice +spline +splint +splinter +split +splodge +splosh +splotch +splurge +splutter +spoil +spoliate +sponge +sponsor +spoof +spook +spool +spoon +spoon-feed +spoor +spore +sport +sporulate +spot +spot-weld +spotlight +spouse +spout +sprain +sprawl +spray +spread +spreadeagle +sprig +spring +spring-clean +sprinkle +sprint +sprout +spruce +spruik +sprung +spud +spue +spume +spur +spurn +spurt +sputter +spy +squabble +squall +squander +square +squaredance +squash +squat +squawk +squeak +squeal +squeeze +squelch +squiggle +squilgee +squint +squire +squirm +squirt +squish +stab +stabilize +stable +stablish +stack +staff +stage +stagemanage +stagger +stagnate +stain +stake +stale +stalemate +stalk +stall +stallfeed +stammer +stamp +stampede +stanchion +stand +standardize +stang +staple +star +starch +stare +stargaze +start +startle +starve +stash +state +station +staunch +stave +stay +stead +steady +steal +steam +steam-heat +steamroller +steamroller +steel +steep +steepen +steeplechase +steer +steeve +stellify +stem +stencil +stenograph +step +stereochrome +stereotype +sterilize +stet +stevedore +stew +steward +stick +stickle +sticky +stiffen +stifle +stigmatize +still +stillhunt +stilt +stimulate +sting +stint +stipple +stipulate +stir +stitch +stithy +stock +stockade +stockpile +stodge +stoke +stomach +stomp +stone +stone-wall +stonewall +stonk +stooge +stook +stool +stoop +stop +stope +stopper +store +storm +story +stot +stoush +stove +stow +straddle +strafe +straggle +straightarm +straighten +strain +straiten +strand +strangle +strangulate +strap +stratify +stravaig +straw +stray +streak +stream +streamline +strengthen +stress +stretch +strew +striate +strickle +stride +stridulate +strike +string +strip +stripe +strive +stroke +stroll +strongarm +strop +strow +stroy +structure +struggle +strum +strut +stub +stucco +stud +study +stuff +stultify +stum +stumble +stump +stun +stunk +stunt +stupefy +stutter +sty +style +stylize +stylopize +stymy +sub +subclass +subcontract +subculture +subdivide +subduct +subdue +subedit +suberize +subinfeudate +subirrigate +subject +subjectify +subjoin +subjugate +sublease +sublet +sublimate +sublime +submerse +subminiaturize +submit +subordinate +suborn +subpoena +subrogate +subscribe +subserve +subside +subsidize +subsist +subsoil +substantialize +substantiate +substantivize +substitute +substract +subsume +subtend +subtilize +subtitle +subtotal +subtract +suburbanize +subvene +subvert +succeed +succour +succumb +succuss +suck +sucker +suckle +sue +suffer +suffice +suffix +sufflate +suffocate +suffumigate +suffuse +sugar +sugarcoat +suggest +suit +sulk +sully +sulphate +sulphonate +sulphurate +sulphuret +sulphurize +sum +summarize +summer +summersault +summersault +summons +summons +sun +sunbathe +sunder +sunk +sup +superabound +superadd +superannuate +supercalender +supercede +supercharge +supercool +supererogate +superfuse +superheat +superimpose +superinduce +superintend +superordinate +superpose +superscribe +supersede +superstruct +supervene +supervise +supinate +supper +supplant +supplement +supplicate +supply +support +suppose +suppress +suppurate +surcease +surcharge +surcingle +surf +surface +surfeit +surge +surmise +surmount +surname +surpass +surprint +surprise +surrender +surrogate +surround +surtax +survey +survive +suspect +suspend +suspire +suss +sustain +susurrate +suture +swab +swaddle +swag +swage +swagger +swallow +swamp +swank +swap +swarm +swarth +swash +swat +swathe +sway +swear +sweaway +sweep +sweeten +sweettalk +swell +swelter +swerve +swig +swill +swim +swindle +swing +swinge +swingle +swink +swipe +swirl +swish +switch +swive +swivel +swizzle +swob +swoon +swoop +swoosh +swop +swot +swound +syllabify +syllabize +syllable +syllogize +symbol +symbolize +symmetrize +sympathize +sync +synchronize +syncopate +syncretize +syndicate +synonymize +synopsize +synthetize +sypher +syphon +syringe +syrup +systemize +table +tabu +tabulate +tack +tackle +tag +tailor +taint +take +talc +talk +tallage +tallow +tally +tallyho +tambour +tame +tamp +tamper +tampon +tan +tangle +tango +tantalize +tap +tape +taper +tar +tare +target +tariff +tarmac +tarnish +tarry +tartarize +task +tassel +taste +tat +tatter +tattle +tattoo +taunt +tauten +tautologize +taway +taws +tawse +tax +taxi +te-hee +teach +team +tear +tease +teasel +ted +tee +teem +teeter +teethe +telecasted +telegraph +telemeter +telepathize +telephone +telescope +teletype +televise +telex +tell +tellurize +telpher +temper +tempest +temporize +tempt +tenant +tend +tender +tenderize +tenon +tense +tent +tenter +tepefy +tergiversate +term +terminate +terrace +terrify +territorialize +terrorize +tessellate +test +testdrive +testfire +testify +testmarket +tetanize +tether +teutonize +thank +thatch +thaw +theologize +theorize +thermalize +thicken +thieve +thin +think +thirl +thirst +thole +thrall +thrash +thread +threat +threaten +threep +thresh +thrill +thrive +throb +thrombose +throne +throng +throttle +throve +throw +throwaway +throwback +thrum +thrust +thud +thumb +thumbindex +thump +thunder +thwack +thwart +tick +ticket +tickle +ticktock +tide +tidy +tie +tier +tiff +tighten +tile +till +tiller +tilt +timber +time +tin +tinct +tincture +ting +tinge +tingle +tinker +tinkle +tinplate +tinsel +tint +tip +tipple +tiptoe +tire +tissue +tithe +titillate +titivate +title +titrate +titter +tittivate +tittletattle +tittup +toady +toast +toboggan +toddle +toe +toe-dance +toenail +tog +toggle +toil +token +tolerate +toll +tomb +tone +tong +tongue +tongue-lash +tonsure +tool +toot +tooth +tootle +top +topdress +tope +topple +topsoil +torch +torment +torpedo +torrify +torture +toss +tot +total +totalize +tote +totter +touch +touchdown +touchtype +toughen +tour +tourney +tousle +tout +touzle +tow +towel +trace +track +trade +trademark +traduce +traffic +trail +train +traipse +traject +tram +trammel +tramp +trample +trampoline +trance +tranquillize +transact +transcend +transcribe +transect +transfer +transfigure +transfix +transform +transfuse +transgress +transilluminate +transistorize +transit +translate +transliterate +translocate +transmigrate +transmit +transmogrify +transmute +transpierce +transpire +transplant +transport +transpose +transship +transubstantiate +transude +transvalue +trap +trapan +trapes +trash +traumatize +travail +travel +traverse +travesty +trawl +tread +treadle +treasure +treat +treble +tree +trek +trellis +tremble +trench +trend +trepan +trephine +trespass +triangulate +trice +trichinize +trick +trickle +tricycle +trifle +trig +trigger +trill +trim +trip +triple +triple-tongue +triplicate +trisect +tritiate +triturate +triumph +trivialize +troat +trode +trog +troll +troop +tropicalize +trot +trouble +trounce +troupe +trow +trowel +truant +truck +truckle +trudge +true +trump +trumpet +truncate +truncheon +trundle +truss +trust +try +tryst +tub +tube +tubulate +tuck +tucker +tuft +tug +tumble +tumefy +tun +tune +tunnel +tup +turf +turmoil +turn +turpentine +turtle +tusk +tussle +tut +tut-tut +tutor +twaddle +twang +tweak +tweet +tweeze +twiddle +twig +twill +twin +twine +twinge +twinkle +twirl +twist +twit +twitch +twitter +twotime +type +typecast +typeset +typewrite +typify +tyrannize +tyre +uglify +ulcerate +ullage +ululate +umpire +unarm +unbalance +unbar +unbelt +unbend +unbind +unbolt +unbonnet +unbosom +unbrace +unbridle +unbuckle +unburden +unbutton +uncap +unchain +unchurch +unclasp +unclog +unclose +unclothe +uncoil +uncork +uncouple +uncover +uncurl +undeceive +underachieve +underact +underbid +underbuy +undercapitalize +undercharge +undercoat +undercool +undercut +underdevelop +underdrain +underestimate +underexpose +underfeed +underfund +undergird +undergo +underlay +underlet +underlie +underline +undermine +undernourish +underpay +underperform +underpin +underplay +underprice +underprop +underquote +underrate +underscore +underseal +undersell +underset +undershot +undersign +understand +understate +understock +understudy +undertake +undertrump +undervalue +underwrite +undo +undock +undress +undulate +unearth +unfasten +unfetter +unfit +unfix +unfold +unfreeze +unfrock +unfurl +unhair +unhallow +unhand +unharness +unhelm +unhinge +unhook +unhorse +uniform +unify +unionize +unite +universalize +unkennel +unknit +unlace +unlade +unlash +unlatch +unlay +unlead +unlearn +unleash +unlimber +unlive +unload +unlock +unloosen +unmake +unman +unmask +unmoor +unmuzzle +unnerve +unpack +unpeg +unpeople +unpick +unpin +unplug +unquote +unravel +unreason +unreeve +unriddle +unrig +unrip +unroll +unroot +unsaddle +unsay +unscramble +unscrew +unseal +unseam +unseat +unsettle +unsex +unsheathe +unship +unsling +unsnap +unsnarl +unspeak +unsphere +unsteady +unsteel +unstep +unstick +unstop +unstring +unsubscribe +unswear +untangle +unteach +unthink +unthread +unthrone +untidy +untie +untread +untruss +untuck +unveil +unvoice +unwind +unwish +unwrap +unyoke +unzip +up +up-anchor +upbraid +upbuild +upcast +update +upend +upgrade +upheave +uphold +upholster +uplift +uppercase +uppercut +upraise +uprear +upright +uprise +uproot +uprouse +upsert +upset +upspring +upstage +upstart +upsurge +upsweep +upswell +upswing +uptilt +upturn +urbanize +urge +urinate +urticate +used +usher +usurp +utilize +utter +unlink +vacate +vacation +vaccinate +vacillate +vacuum +vail +valet +validate +valorize +valuate +value +vamoose +vamp +vandalize +vanish +vanquish +vaporize +variegate +variolate +varitype +varnish +vary +vassalize +vat +vaticinate +vault +vaunt +vector +veer +vegetate +veil +vein +velarize +vellicate +vend +veneer +venerate +venge +vent +ventilate +ventriloquize +venture +verbalize +verbify +verge +verify +verjuice +vermiculate +vernalize +verse +versify +vesicate +vesiculate +vest +vesture +vet +veto +vex +vibrate +victimize +victual +videotape +vie +view +vignette +vilify +vilipend +vindicate +vinegar +vintage +violate +visa +vise +vision +visit +visor +visualize +vitalize +vitiate +vitrify +vitriol +vitriolize +vittle +vituperate +vivify +vivisect +vizor +vocalize +vociferate +voice +void +volatilize +volcanize +volley +volplane +volunteer +vomit +voodoo +vote +vouch +vouchsafe +vow +vowelize +voyage +vulcanize +vulgarize +wabble +wad +waddle +waddy +wade +wadset +wafer +waff +waffle +waft +wag +wage +wager +waggle +waggon +wagon +wail +wainscot +wait +waive +wake +waken +wale +walk +wall +wallop +wallow +wallpaper +waltz +wamble +wan +wander +wane +wangle +wank +wanna +want +wanton +warble +ward +ware +warehouse +warm +warn +warp +warrant +warsle +wash +wassail +waste +watch +water +watercool +watermark +waterproof +waterski +watersoak +wattle +waul +wave +waver +wawa +wawl +wax +waxen +waylay +weaken +wean +wear +weary +weather +weathercock +weatherproof +weave +web +wed +wedge +wee-wee +weed +weed +weekend +ween +weep +weigh +weight +welch +welcome +weld +well +welsh +welt +welter +wench +wend +wester +westernize +wet +wetnurse +whack +whale +wham +whang +whap +wharf +wheedle +wheel +wheelbarrow +wheeze +whelm +whelp +wherrit +whet +whicker +whiff +whiffle +whimper +whine +whinge +whinny +whip +whipsaw +whipstitch +whirl +whirr +whish +whisk +whisper +whist +whistle +whistlestop +white +whiten +whitewash +whittle +whizz +wholesale +whoop +whop +whore +widen +widow +wield +wig +wiggle +wigwag +wildcat +wilder +wile +will +wilt +wimble +wimple +win +wince +winch +wind +windlass +windmill +window +windowshop +windrow +wine +wing +wink +winkle +winnow +winter +winterfeed +winterize +winterkill +wipe +wire +wiredraw +wireless +wis +wise +wisecrack +wish +wisp +wist +witch +withdraw +withe +wither +withhold +withstand +witness +wive +wizen +wobble +wolf +wolfwhistle +woman +womanize +wonder +wont +woo +wood +woof +woosh +word +work +work-to-rule +workharden +worm +worrit +worry +worsen +worship +worst +worth +would +wouldst +wow +wrack +wrangle +wrapped +wrapped +wreak +wreathe +wreck +wrench +wrest +wrestle +wrick +wriggle +wring +wrinkle +writ +write +writhe +writhen +wrong +wrongfoot +wrought +wry +x-ray +xerox +xylograph +yabber +yacht +yack +yammer +yank +yap +yarn +yaup +yaw +yawl +yawn +yawp +yean +yearn +yell +yellow +yelp +yield +yirr +yoke +york +yowl +zap +zero +zest +zigzag +zindabad +zing +zip +zone +zoom +zugzwang diff --git a/lib/rubocop/cop/mixin/helpers.rb b/lib/rubocop/cop/mixin/helpers.rb new file mode 100644 index 0000000..23e1c5e --- /dev/null +++ b/lib/rubocop/cop/mixin/helpers.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Helpers + VERBS = File.read("#{__dir__}/files/verbs.txt").split + + def rails_callback?(callback) + return true if callback == 'validate' + + callback.match?( + / + ^(before|after|around) + _.* + (action|validation|create|update|save|destroy|commit|rollback)$ + /x + ) + end + + def verb?(string) + short_string = string[2..] if string.start_with?('re') + + VERBS.include?(string) || VERBS.include?(short_string) + end + end + end +end diff --git a/lib/rubocop/cop/obsession/graphql/mutation_name.rb b/lib/rubocop/cop/obsession/graphql/mutation_name.rb new file mode 100644 index 0000000..d367ce6 --- /dev/null +++ b/lib/rubocop/cop/obsession/graphql/mutation_name.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Obsession + module Graphql + # This cop checks for mutation names that do not start with a verb. + # + # Mutation names should start with a verb, because mutations are actions, + # and actions are best described with verbs. + # + # @example + # + # # bad + # module Mutations + # class Event < Base + # end + # end + # + # # good + # module Mutations + # class TrackEvent < Base + # end + # end + class MutationName < Cop + include Helpers + + MSG = 'Mutation name should start with a verb.' + + def on_class(class_node) + class_name = class_node.identifier.source + class_name_first_word = class_name.underscore.split('_').first + + add_offense(class_node) if !verb?(class_name_first_word) + end + end + end + end + end +end diff --git a/lib/rubocop/cop/obsession/method_order.rb b/lib/rubocop/cop/obsession/method_order.rb new file mode 100644 index 0000000..f8d9853 --- /dev/null +++ b/lib/rubocop/cop/obsession/method_order.rb @@ -0,0 +1,244 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Obsession + # This cop checks for private/protected methods that are not ordered correctly. + # + # Code should read from top to bottom: methods should be defined in the + # same order as the order when they are first mentioned. + # Private/protected methods should follow that rule. + # + # Note 1: public methods do not have to follow that rule, and can be + # defined in any order the developer wants, like by order of + # importance. This is because they are usually called outside of the + # class and often not called within the class at all. If possible though, + # developers should still try to order their public methods from top to + # bottom when it makes sense. + # + # Note 2: method order cannot be computed for methods called by `send`, + # metaprogramming, private methods called by superclasses or modules, + # etc. This cop's suggestions and autocorrections may be slightly off for + # these kinds of edge cases. + # + # Note 3: for more information on this style of method ordering, see + # Robert C. Martin's "Clean Code" book > "Chapter 3: Functions" > "One + # level of abstraction per function" > "Reading Code from Top to Bottom: + # The Stepdown Rule" chapter. + # + # @example + # + # # bad + # def perform + # return if method_a? + # method_b + # method_c + # end + # + # private + # + # def method_c; ...; end + # def method_b; ...; end + # def method_a?; ...; end + # + # # good + # def perform + # return if method_a? + # method_b + # method_c + # end + # + # private + # + # def method_a?; ...; end + # def method_b; ...; end + # def method_c; ...; end + class MethodOrder < Base + include Helpers + include RangeHelp + include VisibilityHelp + extend AutoCorrector + + MSG = 'Method `%s` should appear below `%s`.' + + def_node_search :private_node, <<~PATTERN + (send nil? {:private :protected}) + PATTERN + + def_node_matcher :on_callback, <<~PATTERN + (send nil? $_ (sym $_) ...) + PATTERN + + def_node_search :method_calls, <<~PATTERN + (send nil? $_ ...) + PATTERN + + class Node + attr_accessor :value, :children + + def initialize(value:, children: []) + @value = value + @children = children + end + end + + def on_class(class_node) + @class_node = class_node + find_private_node || return + build_methods || return + build_callback_methods + + build_method_call_tree + build_ordered_private_methods + build_private_methods + + verify_private_methods_order + end + + private + + def find_private_node + @private_node = private_node(@class_node)&.first + end + + def build_methods + @methods = {} + return false if @class_node&.body&.type != :begin + + @class_node.body.children.each do |child| + @methods[child.method_name] = child if child.type == :def + end + + @methods.any? + end + + def build_callback_methods + @callback_methods = [] + + @class_node.body.children.each do |node| + on_callback(node) do |callback, method_name| + if rails_callback?(callback.to_s) && @methods[method_name] + @callback_methods << @methods[method_name] + end + end + end + end + + def build_method_call_tree + methods = (@callback_methods + @methods.values).uniq + + @method_call_tree = + Node.new(value: nil, children: methods.map { |method| method_call_tree(method) }) + end + + def method_call_tree(method_node, seen_method_calls = Set.new) + method_name = method_node.method_name + return nil if seen_method_calls.include?(method_name) + called_methods = find_called_methods(method_node) + return Node.new(value: method_node, children: []) if called_methods.empty? + + children = + called_methods.filter_map do |called_method| + method_call_tree(called_method, seen_method_calls + [method_name]) + end + + Node.new(value: method_node, children: children) + end + + def find_called_methods(method_node) + called_methods = + method_calls(method_node).filter_map { |method_call| @methods[method_call] } + + @called_methods ||= Set.new(@callback_methods) + @called_methods += called_methods + + called_methods + end + + def build_ordered_private_methods + @ordered_private_methods = ordered_private_methods(@method_call_tree) + end + + def ordered_private_methods(node) + ast_node = node.value + method_name = should_ignore?(ast_node) ? nil : ast_node.method_name + + next_names = node.children.flat_map { |child| ordered_private_methods(child) } + + ([method_name] + next_names).compact.uniq + end + + def should_ignore?(ast_node) + ast_node.nil? || node_visibility(ast_node) == :public || + !@called_methods.include?(ast_node) + end + + def build_private_methods + @private_methods = @methods.keys.intersection(@ordered_private_methods) + end + + def verify_private_methods_order + @ordered_private_methods.each_with_index do |ordered_method, ordered_index| + index = @private_methods.index(ordered_method) + + add_method_offense(ordered_method, ordered_index) && return if index != ordered_index + end + end + + def add_method_offense(method_name, method_index) + method = @methods[method_name] + previous_method = + if method_index > 0 + previous_method_name = @ordered_private_methods[method_index - 1] + @methods[previous_method_name] + else + @private_node + end + + message = format(MSG, previous: previous_method.method_name, after: method_name) + + add_offense(method, message: message) do |corrector| + autocorrect(corrector, method, previous_method) + end + end + + def autocorrect(corrector, method, previous_method) + previous_method_range = source_range_with_comment(previous_method) + method_range = source_range_with_comment(method) + + corrector.insert_after(previous_method_range, method_range.source) + corrector.remove(method_range) + end + + def source_range_with_comment(node) + range_between(start_position_with_comment(node), end_position(node) + 1) + end + + def start_position_with_comment(node) + first_comment = nil + + (node.first_line - 1).downto(1) do |annotation_line| + comment = processed_source.comment_at_line(annotation_line) + break if !comment + first_comment = comment if whole_line_comment_at_line?(annotation_line) + end + + start_line_position(first_comment || node) + end + + def whole_line_comment_at_line?(line) + /\A\s*#/.match?(processed_source.lines[line - 1]) + end + + def start_line_position(node) + processed_source.buffer.line_range(node.loc.line).begin_pos - 1 + end + + def end_position(node) + end_line = processed_source.buffer.line_for_position(node.loc.expression.end_pos) + processed_source.buffer.line_range(end_line).end_pos + end + end + end + end +end diff --git a/lib/rubocop/cop/obsession/no_break_or_next.rb b/lib/rubocop/cop/obsession/no_break_or_next.rb new file mode 100644 index 0000000..1263e61 --- /dev/null +++ b/lib/rubocop/cop/obsession/no_break_or_next.rb @@ -0,0 +1,94 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Obsession + # This cop checks for `next` (and sometimes `break`) in loops. + # + # - For big loops, `next` or `break` indicates that the loop body has + # significant logic, which means it should be moved into its own method, + # and you can convert the `next` or `break` into `return` and the like. + # - For small loops, you can just use normal conditions instead of `next`. + # `break` is allowed. + # + # Note: Sometimes loops can also be rethought, like transforming a `loop` + # + `break` into a `while`. + # + # @example + # + # # bad + # github_teams.each do |github_team| + # next if github_team['size'] == 0 + # team = @company.teams.find_or_initialize_by(github_team['id']) + # + # team.update!( + # name: github_team['name'], + # description: github_team['description'], + # owner: @company, + # ) + # end + # + # # good + # github_teams.each do |github_team| { |github_team| upsert_team(github_team) } + # + # def upsert_team(github_team) + # return if github_team['size'] == 0 + # team = @company.teams.find_or_initialize_by(github_team['id']) + # + # team.update!( + # name: github_team['name'], + # description: github_team['description'], + # owner: @company, + # ) + # end + # + # # bad + # def highlight + # blog_posts.each do |blog_post| + # next if !blog_post.published? + # + # self.highlighted = true + # end + # end + # + # # good + # def highlight + # blog_posts.each do |blog_post| + # if blog_post.published? + # self.highlighted = true + # end + # end + # end + class NoBreakOrNext < Cop + BIG_LOOP_MSG = + 'Avoid `break`/`next` in big loop, decompose into private method or rethink loop.' + NO_NEXT_MSG = 'Avoid `next` in loop, use conditions or rethink loop.' + BIG_LOOP_MIN_LINES = 7 + + def_node_matcher :contains_break_or_next?, <<~PATTERN + `(if <({next break}) ...>) + PATTERN + + def_node_matcher :contains_next?, <<~PATTERN + `(if <(next) ...>) + PATTERN + + def on_block(node) + return if !contains_break_or_next?(node) + + if big_loop?(node) + add_offense(node, message: BIG_LOOP_MSG) + elsif contains_next?(node) + add_offense(node, message: NO_NEXT_MSG) + end + end + + private + + def big_loop?(node) + node.line_count >= BIG_LOOP_MIN_LINES + 2 + end + end + end + end +end diff --git a/lib/rubocop/cop/obsession/no_paragraphs.rb b/lib/rubocop/cop/obsession/no_paragraphs.rb new file mode 100644 index 0000000..742a155 --- /dev/null +++ b/lib/rubocop/cop/obsession/no_paragraphs.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Obsession + # This cop checks for methods with many instructions but no paragraphs. + # + # If your method code has many instructions that are not organized into + # paragraphs, you should break it up into multiple paragraphs to make the + # code more breathable and readable. The 3 possible paragraphs themes + # always are: initialization, action, and result. + # + # @example + # + # # bad + # def set_seo_content + # return if slug.blank? + # return if seo_content.present? + # template = SeoTemplate.find_by(template_type: 'BlogPost') + # return if template.blank? + # self.seo_content = build_seo_content(seo_template: template, slug: slug) + # Rails.logger.info('Content has been set') + # end + # + # # good + # def set_seo_content + # return if slug.blank? + # return if seo_content.present? + # template = SeoTemplate.find_by(template_type: 'BlogPost') + # return if template.blank? + # + # self.seo_content = build_seo_content(seo_template: template, slug: slug) + # + # Rails.logger.info('Content has been set') + # end + class NoParagraphs < Cop + MSG = 'Method has many instructions and should be broken up into paragraphs.' + MAX_CONSECUTIVE_INSTRUCTIONS_ALLOWED = 5 + + def on_def(node) + lines = processed_source.lines[node.first_line..(node.last_line - 2)] + return if lines.any?(&:blank?) + node_body_type = node&.body&.type + return if %i[send if or case array hash].include?(node_body_type) + return if %w[asgn str].any? { |string| node_body_type.to_s.include?(string) } + + too_big = + case node_body_type + when :begin, :block, :rescue + node.body.children.count > MAX_CONSECUTIVE_INSTRUCTIONS_ALLOWED && + !node.body.children.all? { |child| child.type.to_s.include?('asgn') } + else + lines.count > MAX_CONSECUTIVE_INSTRUCTIONS_ALLOWED + end + + add_offense(node) if too_big + end + alias_method :on_defs, :on_def + end + end + end +end diff --git a/lib/rubocop/cop/obsession/no_todos.rb b/lib/rubocop/cop/obsession/no_todos.rb new file mode 100644 index 0000000..ec9d75f --- /dev/null +++ b/lib/rubocop/cop/obsession/no_todos.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Obsession + # This cop checks for TODO/FIXME/etc comments. + # + # Avoid TODO comments, instead create tasks for them in your project + # management software, and assign them to the right person. Half of the + # TODOs usually never get done, and the code is then polluted with old + # stale TODOs. Sometimes developers really mean to work on their TODOs + # soon, but then Product re-prioritizes their work, or the developer + # leaves the company, and never gets a chance to tackle them. + class NoTodos < Cop + MSG = 'Avoid TODO comment, create a task in your project management tool instead.' + KEYWORD_REGEX = /(^|[^\w])(TODO|FIXME|OPTIMIZE|HACK)($|[^\w])/i + + def on_new_investigation + processed_source.comments.each do |comment| + add_offense(comment) if comment.text.match?(KEYWORD_REGEX) + end + end + end + end + end +end diff --git a/lib/rubocop/cop/obsession/rails/callback_one_method.rb b/lib/rubocop/cop/obsession/rails/callback_one_method.rb new file mode 100644 index 0000000..118f07a --- /dev/null +++ b/lib/rubocop/cop/obsession/rails/callback_one_method.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Obsession + module Rails + # This cop checks for Rails callbacks with multiple fields. + # + # One method per callback definition makes the definition extra clear. + # + # @example + # + # # bad + # after_create :notify_followers, :send_stats + # + # # good + # after_create :notify_followers + # after_create :send_stats + class CallbackOneMethod < Cop + include Helpers + + MSG = 'Declare only one method per callback definition.' + + def_node_matcher :on_callback, <<~PATTERN + (send nil? $_ (sym _) (sym _) ...) + PATTERN + + def on_send(node) + on_callback(node) { |callback| add_offense(node) if rails_callback?(callback.to_s) } + end + end + end + end + end +end diff --git a/lib/rubocop/cop/obsession/rails/fully_defined_json_field.rb b/lib/rubocop/cop/obsession/rails/fully_defined_json_field.rb new file mode 100644 index 0000000..4c6596d --- /dev/null +++ b/lib/rubocop/cop/obsession/rails/fully_defined_json_field.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Obsession + module Rails + # This cop checks for json(b) fields that are not fully defined with + # defaults or comments. + # + # - json(b) fields should have a default value like {} or [] so code can + # do my_field['field'] or my_field.first without fear that my_field is + # nil. + # - It is impossible to know the structure of a json(b) field just by + # reading the schema, because json(b) is an unstructured type. That's why + # an "Example: ..." Postgres comment should always be present when + # defining the field. + # + # @example + # + # # bad + # add_column :languages, :items, :jsonb + # + # # good + # add_column :languages, + # :items, + # :jsonb, + # default: [], + # comment: "Example: [{ 'name': 'ruby' }, { 'name': 'python' }]" + class FullyDefinedJsonField < Cop + def_node_matcher :json_field?, <<~PATTERN + (send nil? :add_column _ _ (sym {:json :jsonb}) ...) + PATTERN + + def_node_matcher :has_default?, <<~PATTERN + (hash <(pair (sym :default) ...) ...>) + PATTERN + + def_node_matcher :has_comment_with_example?, <<~PATTERN + (hash < + (pair + (sym :comment) + `{ + (str /^Example: [\\[\\{].{4,}[\\]\\}]/) | + (dstr (str /^Example: [\\[\\{]/) ... (str /[\\]\\}]/) ) + } + ) + ... + >) + PATTERN + + def on_send(node) + return if !json_field?(node) + options_node = node.children[5] + + if !has_default?(options_node) + add_offense(node, message: 'Add default value of {} or []') + end + + if !has_comment_with_example?(options_node) + add_offense( + node, + message: + 'Add `comment: "Example: "` option with an example array or hash value' + ) + end + end + end + end + end + end +end diff --git a/lib/rubocop/cop/obsession/rails/migration_belongs_to.rb b/lib/rubocop/cop/obsession/rails/migration_belongs_to.rb new file mode 100644 index 0000000..d5e6647 --- /dev/null +++ b/lib/rubocop/cop/obsession/rails/migration_belongs_to.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Obsession + module Rails + # This cop checks for migrations that use `references` instead of `belongs_to`. + # + # Instead of adding `references` in migrations, use the `belongs_to` + # alias. It reads nicer and is more similar to the `belongs_to` + # declarations that you find in model code. + # + # @example + # + # # bad + # def change + # add_reference :blog_posts, :user + # end + # + # # good + # def change + # add_belongs_to :blog_posts, :user + # end + class MigrationBelongsTo < Cop + def_node_matcher :add_reference?, <<~PATTERN + (send nil? :add_reference ...) + PATTERN + + def_node_matcher :table_reference?, <<~PATTERN + (send (lvar :t) :references ...) + PATTERN + + def on_send(node) + if add_reference?(node) + add_offense(node, message: 'Use add_belongs_to instead of add_reference') + elsif table_reference?(node) + add_offense(node, message: 'Use t.belongs_to instead of t.references') + end + end + end + end + end + end +end diff --git a/lib/rubocop/cop/obsession/rails/no_callback_conditions.rb b/lib/rubocop/cop/obsession/rails/no_callback_conditions.rb new file mode 100644 index 0000000..f0ae496 --- /dev/null +++ b/lib/rubocop/cop/obsession/rails/no_callback_conditions.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Obsession + module Rails + # This cop checks for model callbacks with conditions. + # + # Model callback with conditions should be avoided because they can + # quickly degenerate into multiple conditions that pollute the macro + # definition section, even more so if lambdas are involved. Instead, move + # the condition inside the callback method. + # + # Note: conditions are allowed for `validates :field` callbacks, as it is + # sometimes not easy to translate them into `validate :validate_field` + # custom validation callbacks. + # + # @example + # + # # bad + # after_update_commit :crawl_rss, if: :rss_changed? + # def crawl_rss + # ... + # end + # + # # good + # after_update_commit :crawl_rss + # def crawl_rss + # return if !rss_changed? + # ... + # end + class NoCallbackConditions < Cop + MSG = + 'Avoid condition in callback declaration, move it inside the callback method instead.' + + def_node_matcher :callback_with_condition?, <<~PATTERN + ( + send nil? _ + (sym _) + (hash + ... + (pair (sym {:if :unless}) ...) + ... + ) + ) + PATTERN + + def on_send(node) + return if !callback_with_condition?(node) + callback = node.children[1] + return if callback == :validates + return if callback.to_s.include?('around') + + add_offense(node) + end + end + end + end + end +end diff --git a/lib/rubocop/cop/obsession/rails/private_callback.rb b/lib/rubocop/cop/obsession/rails/private_callback.rb new file mode 100644 index 0000000..d49e46e --- /dev/null +++ b/lib/rubocop/cop/obsession/rails/private_callback.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Obsession + module Rails + # This cop checks for callbacks methods that are not private. + # + # Callback methods are usually never called outside of the class, so + # there is no reason to declare them in the public section. They should + # be private. + # + # @example + # + # # bad + # before_action :load_blog_post + # + # def load_blog_post + # ... + # end + # + # # good + # before_action :load_blog_post + # + # private + # + # def load_blog_post + # ... + # end + class PrivateCallback < Cop + include VisibilityHelp + include Helpers + + MSG = 'Make callback method private' + + def_node_matcher :on_callback, <<~PATTERN + (send nil? $_ (sym $_) ...) + PATTERN + + def on_new_investigation + @callbacks = Set.new + end + + def on_send(node) + on_callback(node) do |callback, method_name| + @callbacks << method_name if rails_callback?(callback.to_s) + end + end + + def on_def(node) + if @callbacks.include?(node.method_name) && node_visibility(node) == :public + add_offense(node, message: MSG) + end + end + end + end + end + end +end diff --git a/lib/rubocop/cop/obsession/rails/safety_assured_comment.rb b/lib/rubocop/cop/obsession/rails/safety_assured_comment.rb new file mode 100644 index 0000000..3e8348c --- /dev/null +++ b/lib/rubocop/cop/obsession/rails/safety_assured_comment.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Obsession + module Rails + # This cop checks uses of strong_migrations' `safety_assured { ... }` + # without a valid reason. + # + # `safety_assured { ... }` should only be used after *carefully* + # following the instructions from the strong_migrations gem. Always add a + # `# Safe because ` comment explaining how you assured the safety + # of the DB migration. The reason should be detailed and reviewed by a + # knowledgeable PR reviewer. Failure to follow instructions may bring your + # app down. + class SafetyAssuredComment < Cop + MSG = + 'Add `# Safe because ` comment above safety_assured. ' \ + 'An invalid reason may bring the site down.' + + def_node_matcher :safety_assured_block?, <<~PATTERN + (block (send nil? :safety_assured) ...) + PATTERN + + def on_block(node) + return if !safety_assured_block?(node) + previous_comment = processed_source.comments_before_line(node.first_line)&.first + + if previous_comment.nil? || !previous_comment.text.match?(/^# Safe because( [^ ]+){4}/) + add_offense(node) + end + end + end + end + end + end +end diff --git a/lib/rubocop/cop/obsession/rails/service_name.rb b/lib/rubocop/cop/obsession/rails/service_name.rb new file mode 100644 index 0000000..fb8adce --- /dev/null +++ b/lib/rubocop/cop/obsession/rails/service_name.rb @@ -0,0 +1,82 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Obsession + module Rails + # This cop checks for services and jobs whose name do not start with a verb. + # + # Services and jobs with only one public method should have a name that + # starts with a verb, because these classes are essentially performing + # one action, and the best way to describe an action is with a verb. + # + # @example + # + # # bad + # class Company + # def perform + # ... + # end + # end + # + # # good + # class ImportCompany + # def perform + # ... + # end + # end + # + # # bad + # class BlogPostPopularityJob < ApplicationJob + # def perform + # ... + # end + # end + # + # # good + # class UpdateBlogPostPopularityJob < ApplicationJob + # def perform + # ... + # end + # end + class ServiceName < Base + include Helpers + + MSG = 'Service or Job name should start with a verb.' + IGNORED_PUBLIC_METHODS = %i[initialize lock_period].freeze + + def_node_matcher :private_section?, <<~PATTERN + (send nil? {:private :protected}) + PATTERN + + def on_class(class_node) + return if public_methods(class_node).length != 1 + class_name = class_node.identifier.source + class_name_first_word = class_name.underscore.split('_').first + + add_offense(class_node) if !verb?(class_name_first_word) + end + + private + + def public_methods(class_node) + return [] if !class_node.body + public_methods = [] + + case class_node.body.type + when :def + public_methods << class_node.body + when :begin + class_node.body.children.each do |child| + public_methods << child if child.type == :def + break if private_section?(child) + end + end + + public_methods.reject { |method| IGNORED_PUBLIC_METHODS.include?(method.method_name) } + end + end + end + end + end +end diff --git a/lib/rubocop/cop/obsession/rails/service_perform_method.rb b/lib/rubocop/cop/obsession/rails/service_perform_method.rb new file mode 100644 index 0000000..d1712bd --- /dev/null +++ b/lib/rubocop/cop/obsession/rails/service_perform_method.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Obsession + module Rails + # This cop checks for services whose single public method is not named + # `perform`. + # + # Services and jobs with only one public method should have their method + # named `perform` for consistency. The choice of `perform` as a name is + # inspired from ActiveJob and makes it easier to make services and jobs + # interchangeable. + # + # @example + # + # # bad + # class ImportCompany + # def import + # ... + # end + # end + # + # # bad + # class ImportCompany + # def execute + # ... + # end + # end + # + # # good + # class ImportCompany + # def perform + # ... + # end + # end + class ServicePerformMethod < ServiceName + extend AutoCorrector + + MSG = 'Single public method of Service should be called `perform`' + + def on_class(class_node) + public_methods = public_methods(class_node) + return if public_methods.length != 1 + method = public_methods.first + + if method.method_name != :perform + add_offense(method) do |corrector| + corrector.replace(method, method.source.sub(/#{method.method_name}/, 'perform')) + end + end + end + end + end + end + end +end diff --git a/lib/rubocop/cop/obsession/rails/short_after_commit.rb b/lib/rubocop/cop/obsession/rails/short_after_commit.rb new file mode 100644 index 0000000..0116f7f --- /dev/null +++ b/lib/rubocop/cop/obsession/rails/short_after_commit.rb @@ -0,0 +1,90 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Obsession + module Rails + # This cop checks for `after_commit` declarations that could be shorter. + # + # @example + # + # # bad + # after_commit :send_email, on: :create + # + # # good + # after_create_commit :send_email + class ShortAfterCommit < Cop + MSG = 'Use shorter %s' + + def_node_matcher :after_commit?, '(send nil? :after_commit ...)' + + def_node_matcher :after_commit_create?, <<~PATTERN + ( + send nil? :after_commit + (sym _) + (hash + (pair (sym :on) {(sym :create)|(array (sym :create))}) + ) + ) + PATTERN + + def_node_matcher :after_commit_update?, <<~PATTERN + ( + send nil? :after_commit + (sym _) + (hash + (pair (sym :on) {(sym :update)|(array (sym :update))}) + ) + ) + PATTERN + + def_node_matcher :after_commit_destroy?, <<~PATTERN + ( + send nil? :after_commit + (sym _) + (hash + (pair (sym :on) {(sym :destroy)|(array (sym :destroy))}) + ) + ) + PATTERN + + def_node_matcher :after_commit_create_update?, <<~PATTERN + ( + send nil? :after_commit + (sym _) + (hash + (pair (sym :on) (array <(sym :create) (sym :update)>)) + ) + ) + PATTERN + + def_node_matcher :after_commit_all_events?, <<~PATTERN + ( + send nil? :after_commit + (sym _) + (hash + (pair (sym :on) (array <(sym :create) (sym :update) (sym :destroy)>)) + ) + ) + PATTERN + + def on_send(node) + return if !after_commit?(node) + + if after_commit_create?(node) + add_offense(node, message: format(MSG, prefer: 'after_create_commit')) + elsif after_commit_update?(node) + add_offense(node, message: format(MSG, prefer: 'after_update_commit')) + elsif after_commit_destroy?(node) + add_offense(node, message: format(MSG, prefer: 'after_destroy_commit')) + elsif after_commit_create_update?(node) + add_offense(node, message: format(MSG, prefer: 'after_save_commit')) + elsif after_commit_all_events?(node) + add_offense(node, message: format(MSG, prefer: 'after_commit with no `on:` argument')) + end + end + end + end + end + end +end diff --git a/lib/rubocop/cop/obsession/rails/short_validate.rb b/lib/rubocop/cop/obsession/rails/short_validate.rb new file mode 100644 index 0000000..6f35bd1 --- /dev/null +++ b/lib/rubocop/cop/obsession/rails/short_validate.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Obsession + module Rails + # This cop checks for `validate` declarations that could be shorter. + # + # @example + # + # # bad + # validate :validate_url, on: %i(create update) + # + # # good + # validate :validate_url + class ShortValidate < Cop + MSG = 'The `on:` argument is not needed in this validate.' + + def_node_matcher :validate_with_unneeded_on?, <<~PATTERN + ( + send nil? :validate + (sym _) + (hash + (pair (sym :on) (array <(sym :create) (sym :update)>)) + ) + ) + PATTERN + + def on_send(node) + add_offense(node) if validate_with_unneeded_on?(node) + end + end + end + end + end +end diff --git a/lib/rubocop/cop/obsession/rails/validate_one_field.rb b/lib/rubocop/cop/obsession/rails/validate_one_field.rb new file mode 100644 index 0000000..ded0465 --- /dev/null +++ b/lib/rubocop/cop/obsession/rails/validate_one_field.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Obsession + module Rails + # This cop checks for `validates` callbacks with multiple fields. + # + # One field per `validates` makes the validation extra clear. + # + # @example + # + # # bad + # validates :name, :status, presence: true + # + # # good + # validates :name, presence: true + # validates :status, presence: true + class ValidateOneField < Cop + MSG = 'Validate only one field per line.' + + def_node_matcher :validates_with_more_than_one_field?, <<~PATTERN + (send nil? :validates (sym _) (sym _) ...) + PATTERN + + def on_send(node) + add_offense(node) if validates_with_more_than_one_field?(node) + end + end + end + end + end +end diff --git a/lib/rubocop/cop/obsession/rails/validation_method_name.rb b/lib/rubocop/cop/obsession/rails/validation_method_name.rb new file mode 100644 index 0000000..567f57c --- /dev/null +++ b/lib/rubocop/cop/obsession/rails/validation_method_name.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Obsession + module Rails + # This cop checks for validation methods that do not start with `validate_`. + # + # @example + # + # # bad + # validate :at_least_one_admin + # + # # good + # validate :validate_at_least_one_admin + class ValidationMethodName < Cop + MSG = 'Prefix custom validation method with validate_' + + def_node_matcher :on_validate_callback, <<~PATTERN + (send nil? :validate (sym $_) ...) + PATTERN + + def on_send(node) + on_validate_callback(node) do |method_name| + add_offense(node) if !method_name.start_with?('validate_') + end + end + end + end + end + end +end diff --git a/lib/rubocop/cop/obsession/rspec/describe_public_method.rb b/lib/rubocop/cop/obsession/rspec/describe_public_method.rb new file mode 100644 index 0000000..414c2cf --- /dev/null +++ b/lib/rubocop/cop/obsession/rspec/describe_public_method.rb @@ -0,0 +1,125 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Obsession + module Rspec + # This cop checks for `describe` blocks that test private methods. + # + # If you are doing black box unit testing, it means that you are only + # interested in testing external behavior, a.k.a public interface, + # a.k.a public methods. Private methods are considered implementation + # details and are not directly tested. + # + # If you need to test a Rails callback, test it indirectly through its + # corresponding Rails public method, e.g. #create, #save, etc. + # + # @example + # + # class Comment < ApplicationRecord + # after_create_commit :notify_users + # + # private + # + # def notify_users + # ... + # end + # end + # + # # bad + # describe '#notify_users' do + # ... + # end + # + # # good + # describe '#create' do + # it 'notifies users' do + # ... + # end + # end + class DescribePublicMethod < Cop + MSG = 'Only test public methods.' + + def_node_matcher :on_context_method, <<-PATTERN + (block (send nil? :describe (str $#method_name?)) ...) + PATTERN + + def_node_search :class_nodes, <<~PATTERN + (class ...) + PATTERN + + def_node_matcher :private_section?, <<~PATTERN + (send nil? {:private :protected}) + PATTERN + + def on_block(node) + on_context_method(node) do |method_name| + method_name = method_name.sub('#', '').to_sym + add_offense(node) if private_methods.include?(method_name) + end + end + + private + + def method_name?(description) + description.start_with?('#') + end + + def private_methods + return @private_methods if @private_methods + @private_methods = [] + + if File.exist?(tested_file_path) + node = parse_file(tested_file_path) + @private_methods = find_private_methods(class_nodes(node).first) + end + + @private_methods + end + + def tested_file_path + return @tested_file_path if @tested_file_path + + spec_path = processed_source.file_path.sub(Dir.pwd, '') + file_path = + if spec_path.include?('/lib/') + spec_path.sub('/spec/lib/', '/lib/') + else + spec_path.sub('/spec/', '/app/') + end + file_path = file_path.sub('_spec.rb', '.rb') + file_path = File.join(Dir.pwd, file_path) + + @tested_file_path = file_path + end + + def parse_file(file_path) + parser_class = ::Parser.const_get(:"Ruby#{target_ruby_version.to_s.sub('.', '')}") + parser = parser_class.new(RuboCop::AST::Builder.new) + + buffer = Parser::Source::Buffer.new(file_path, 1) + buffer.source = File.read(file_path) + + parser.parse(buffer) + end + + def find_private_methods(class_node) + return [] if class_node&.body&.type != :begin + private_methods = [] + private_section_found = false + + class_node.body.children.each do |child| + if private_section?(child) + private_section_found = true + elsif child.type == :def && private_section_found + private_methods << child.method_name + end + end + + private_methods + end + end + end + end + end +end diff --git a/lib/rubocop/cop/obsession/rspec/empty_line_after_final_let.rb b/lib/rubocop/cop/obsession/rspec/empty_line_after_final_let.rb new file mode 100644 index 0000000..dce9b89 --- /dev/null +++ b/lib/rubocop/cop/obsession/rspec/empty_line_after_final_let.rb @@ -0,0 +1,36 @@ +if defined?(RuboCop::RSpec) + module RuboCop + module Cop + module Obsession + module Rspec + # Same as RSpec/EmptyLineAfterFinalLet, but allows `let` to be followed + # by `it` with no new line, to allow for this style of spec: + # + # @example + # + # describe '#domain' do + # context do + # let(:url) { Url.new('http://www.some-site.com/some-page') } + # it { expect(url.domain).to eq 'some-site.com' } + # end + # + # context do + # let(:url) { Url.new('some-site.com') } + # it { expect(url.domain).to eq 'some-site.com' } + # end + # end + class EmptyLineAfterFinalLet < RSpec::EmptyLineAfterFinalLet + def missing_separating_line(node) + line = final_end_location(node).line + line += 1 while comment_line?(processed_source[line]) + return if processed_source[line].blank? + return if processed_source[line].match?(/\s*it /) + + yield offending_loc(line) + end + end + end + end + end + end +end diff --git a/lib/rubocop/cop/obsession/too_many_paragraphs.rb b/lib/rubocop/cop/obsession/too_many_paragraphs.rb new file mode 100644 index 0000000..51a6221 --- /dev/null +++ b/lib/rubocop/cop/obsession/too_many_paragraphs.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Obsession + # This cop checks for methods with too many paragraphs. + # + # You should organize your method code into 2 to 3 paragraphs maximum. + # The 3 possible paragraphs themes always are: initialization, action, + # and result. Shape your paragraph according to those themes. Spec code + # should also be organized into 2 to 3 paragraphs + # (initialization/action/result or given/when/then paragraphs). + # + # After organizing your paragraphs, if they are too long or dense, it is + # a sign that you should break your code into smaller methods. + # + # @example + # + # # bad + # def set_seo_content + # return if seo_content.present? + # + # template = SeoTemplate.find_by(template_type: 'BlogPost') + # + # return if template.blank? + # + # self.seo_content = build_seo_content(seo_template: template, slug: slug) + # + # Rails.logger.info('Content has been set') + # end + # + # # good + # def set_seo_content + # return if seo_content.present? + # template = SeoTemplate.find_by(template_type: 'BlogPost') + # return if template.blank? + # + # self.seo_content = build_seo_content(seo_template: template, slug: slug) + # + # Rails.logger.info('Content has been set') + # end + class TooManyParagraphs < Cop + MSG = 'Organize method into 2 to 3 paragraphs (init, action, result).' + MAX_PARAGRAPHS = 3 + + def on_def(node) + lines = processed_source.lines[node.first_line..(node.last_line - 2)] + blank_lines_count = lines.count(&:blank?) + + add_offense(node) if blank_lines_count >= MAX_PARAGRAPHS + end + alias_method :on_defs, :on_def + end + end + end +end diff --git a/lib/rubocop/obsession.rb b/lib/rubocop/obsession.rb index 4e64296..f40e58c 100644 --- a/lib/rubocop/obsession.rb +++ b/lib/rubocop/obsession.rb @@ -1,9 +1,9 @@ require 'active_support' +require 'active_support/core_ext/object/blank' +require 'rubocop' + +require_relative 'cop/mixin/helpers' +Dir["#{__dir__}/cop/obsession/**/*.rb"].sort.each { |file| require file } require_relative 'obsession/version' -module Rubocop - module Obsession - class Error < StandardError - end - end -end +RuboCop::ConfigLoader.inject_defaults!("#{__dir__}/../..") diff --git a/rubocop-obsession.gemspec b/rubocop-obsession.gemspec index ed2ff91..f092f4b 100644 --- a/rubocop-obsession.gemspec +++ b/rubocop-obsession.gemspec @@ -19,5 +19,5 @@ Gem::Specification.new do |spec| spec.require_paths = ['lib'] spec.add_dependency 'activesupport' - spec.add_dependency 'rubocop' + spec.add_dependency 'rubocop', '~> 1.41' end