shoulda_matchmakers 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +21 -0
  4. data/lib/controller/action_controller/action_controller_controller_sm_model.rb +53 -0
  5. data/lib/controller/action_controller/action_controller_controller_sm_model_helper.rb +73 -0
  6. data/lib/controller/action_controller/matchmakers/callbacks.rb +56 -0
  7. data/lib/controller/action_controller/matchmakers/filter_param.rb +69 -0
  8. data/lib/controller/action_controller/matchmakers/permit.rb +510 -0
  9. data/lib/controller/action_controller/matchmakers/redirect_to.rb +126 -0
  10. data/lib/controller/action_controller/matchmakers/render_template.rb +198 -0
  11. data/lib/controller/action_controller/matchmakers/render_with_layout.rb +72 -0
  12. data/lib/controller/action_controller/matchmakers/rescue_from.rb +96 -0
  13. data/lib/controller/action_controller/matchmakers/respond_with.rb +71 -0
  14. data/lib/controller/action_controller/matchmakers/route.rb +586 -0
  15. data/lib/controller/action_controller/matchmakers/set_flash.rb +136 -0
  16. data/lib/controller/action_controller/matchmakers/set_session.rb +115 -0
  17. data/lib/controller/action_controller/permitted_params_definition.rb +60 -0
  18. data/lib/generators/shoulda_matchmakers/controller_matcher_generator.rb +87 -0
  19. data/lib/generators/shoulda_matchmakers/controller_matcher_generator_helper.rb +92 -0
  20. data/lib/generators/shoulda_matchmakers/factory_generator.rb +86 -0
  21. data/lib/generators/shoulda_matchmakers/install_generator.rb +10 -0
  22. data/lib/generators/shoulda_matchmakers/model_matcher_generator.rb +87 -0
  23. data/lib/generators/shoulda_matchmakers/model_matcher_generator_helper.rb +107 -0
  24. data/lib/model/active_record/active_record_model_sm_model.rb +50 -0
  25. data/lib/model/active_record/active_record_model_sm_model_helper.rb +206 -0
  26. data/lib/model/active_record/factory_sm_model.rb +28 -0
  27. data/lib/model/active_record/factory_sm_model_helper.rb +124 -0
  28. data/lib/model/active_record/matchmakers/accept_nested_attributes_for.rb +66 -0
  29. data/lib/model/active_record/matchmakers/allow_value.rb +137 -0
  30. data/lib/model/active_record/matchmakers/associations.rb +52 -0
  31. data/lib/model/active_record/matchmakers/define_enum_for.rb +53 -0
  32. data/lib/model/active_record/matchmakers/delegate_method.rb +101 -0
  33. data/lib/model/active_record/matchmakers/have_db_column.rb +33 -0
  34. data/lib/model/active_record/matchmakers/have_db_index.rb +39 -0
  35. data/lib/model/active_record/matchmakers/have_readonly_attribute.rb +32 -0
  36. data/lib/model/active_record/matchmakers/have_secure_password.rb +32 -0
  37. data/lib/model/active_record/matchmakers/serialize.rb +67 -0
  38. data/lib/model/active_record/matchmakers/validations.rb +169 -0
  39. data/lib/model/active_record/options_definition.rb +160 -0
  40. data/lib/shoulda_matchmakers.rb +48 -0
  41. data/lib/shoulda_matchmakers/version.rb +3 -0
  42. data/lib/support/command_line_interface.rb +100 -0
  43. data/lib/support/controller_generator.rb +198 -0
  44. data/lib/support/indefinite_article.rb +70 -0
  45. data/lib/support/to_discard/belong_to.rb +94 -0
  46. data/lib/support/to_discard/have_and_belong_to_many.rb +83 -0
  47. data/lib/support/to_discard/have_many.rb +96 -0
  48. data/lib/support/to_discard/have_one.rb +98 -0
  49. data/lib/support/to_discard/permit_refactor.rb +270 -0
  50. data/lib/support/to_discard/render_template_new.rb +204 -0
  51. data/lib/support/to_discard/render_template_reconstruction.rb +188 -0
  52. data/lib/support/to_discard/use_around_action.rb +20 -0
  53. data/lib/support/to_discard/use_before_action.rb +20 -0
  54. data/lib/support/to_discard/validate_absence_of.rb +16 -0
  55. data/lib/support/to_discard/validate_acceptance_of.rb +16 -0
  56. data/lib/support/to_discard/validate_confirmation_of.rb +16 -0
  57. data/lib/support/to_discard/validate_exclusion_of.rb +145 -0
  58. data/lib/support/to_discard/validate_inclusion_of.rb +94 -0
  59. data/lib/support/to_discard/validate_length_of.rb +16 -0
  60. data/lib/support/to_discard/validate_numericality_of.rb +16 -0
  61. data/lib/support/to_discard/validate_presence_of.rb +16 -0
  62. data/lib/support/to_discard/validate_uniqueness_of.rb +16 -0
  63. data/lib/support/to_discard/validation_old.rb +37 -0
  64. data/lib/support/to_discard/validations.rb +41 -0
  65. data/lib/support/to_discard/validations_conditional.rb +146 -0
  66. data/lib/support/trace_debug_lines.txt +319 -0
  67. data/lib/support/util.rb +15 -0
  68. data/lib/templates/controller/action_controller/controller_spec_template.haml +146 -0
  69. data/lib/templates/factory/active_record/factory_template.haml +13 -0
  70. data/lib/templates/model/active_record/model_spec_template.haml +233 -0
  71. data/lib/templates/shoulda_matchmakers.rb +112 -0
  72. metadata +263 -0
@@ -0,0 +1,70 @@
1
+ module ShouldaMatchmakers
2
+
3
+ # Source: https://gist.github.com/michaelglass/7905878
4
+ # A vs An ported to ruby from: http://home.nerbonne.org/A-vs-An/
5
+
6
+ # encoding: UTF-8
7
+ # by Eamon Nerbonne (from http://home.nerbonne.org/A-vs-An), Apache 2.0 license
8
+ class IndefiniteArticle
9
+ # Usage example: IndefiniteArticle.for("example ")
10
+ # example returns: "an"
11
+ # Note that the terminal space indicates this is a complete word - this is sometimes significant, particularly for acronyms!
12
+ DICT = "]08[09[0-11[0-4[0-4 ]0-6-[0-8[11[110]111]112]113]114]115]116]117]118]119]11.4]18[180]1800[1801[1802[1803[1804[1805[1806[1807[1808[1809[181-]181 ]182-]182 ]183-]183 ]184-]184 ]185-]185 ]186-]186 ]187-]187 ]188-]188 ]189-]189 ]8[800x]890]8,1]8,2]–i[#i[$11 [$11.[$18 [$18,[$18.[$8[&a[&o[*a[*e[*i[.av[.mp[.og[/a[/e[/h[/i[/l[/s/[@[`a[£8[∞[a[a ]abou]about-[agai]al-I]algu]alth]amon]an ]and]and\"[anda[ande[andr[anot]anyw]apart ]appears]apre]are ]are:]artí]A[A$]AAA]Akiz]Amar\"]Andaluc]Armat]Asturias]Athl]Athleti[Athlo[AU$]AUD]AUSC]Á[á[à[Ä[ā[Å[æ[Æ[Æn]Bhai[Bhá[Buddhism[contains[Chais[County,[das [dem [der [describes[Dinas[Diver-[Dún]e[e.g]each ]either ]either.]el-]ella]empez]enoug]eu]eup [ew]exists]E[Empez]Enam]Esp]Espad[Espe[Espo[Eu]Eul[EUR]é[ég]ét]éta[étu[É[f-[f [f\"[f/[fM[fp[ft[F0[F1[F2[F3[F4[F5[F6[F9[F'[F-[F [F\"[F#[F,[F.[F/[F”[FA[FAC]FAD]FAIR]FAL]FAM]FAN]FAP]FAQ]FAR]FAS]FAT]FB[FC[Fc[FD[FEC[FEI[FF[FF ]Ff[Fh[FH[FIA[FIAT]FID [FIR [FIS [FK[FLC[FLN[FLP[FM[FMR]FO [FOI [FP[FP.]FP?]FPC?]FRC[FRS[FS[FT[FTS]FTT]FU [FU,[FU.[FV[FW[FWD]FX[FY[Fσ[Ghae[Ghai[h'[h-[h-U]h [h\"[h,[hC[heir[heira]hims[historic\"[historic\" ]homa[homm[hon[honey]honk]honv]hors [hour[ht[htt]http [H1[H2[H3[H4[H5[H'[H-[H [H\"[H&[H,[H.[H.A]H+[Habilitations[HB[HC[HD[HDB]Heir[HF[HG[HH[HI[HID]HIG]HIM]HIP]HL[HLA-D]HM[HN[Hon[Hond]Hone]Hones[Hong]Honk]Honol]Hour[HO [HOV[HP[HQ[HR[HRT]HS[HS ]HSR]HST]HT[HTP]HV[HWT[i[i.e]ibn]if ]ii]includi]indicates]instea]instead?[is ]is.]it ]iu]I[I-A]I-I]III]Ilb]IMH]Imams]IR£]Islam ]Islam,]Islam.]Islands]İ[Jia[Jian]ku [l [l\"[lp[L1[L2[L3[L5[L'[L'A]L-[L-a]L [L\"[L&[L,[L.[L/[Lae[Laoig[LA [LAL[LAP[LB[LC[LD[LE[LEA]LEE]LEG]LEO]LEP]LET]LF[LG[LH[LIR[LL[LM[LMX]LN[Locha[LOE[LP[LR[LS[LT[LU [LV[LX[LZ[m-[m [m\"[m&[m×[makes [mb[mein[mentions[mf[mp[mR[mt[M1[M19]M190[M2[M3[M4[M5[M6[M7[M8[M9[M'[M-[M-t]M [M\"[M&[M,[M.[M.A.S]M/[MA[MAC]MAD]MAF]MAG]MAJ]MAL]MAM]MAN]MAP]MAR]MAS]MAT]MAX]MAY]MB[MC[MD[Me-[MEd[MEn[MEP[MF[Mf[MG[MH[Mh[Mie[MI5[MI6[MI [MIA[MIT[MK[ML[MM[MMT]MN[MoU[MO [MOT [MOU[MP[MR[MS[Msc[MT[MTR]MUV[MV[MX[N4[N6[N'[N-[N-a]N-S]N [N\"[N,[N.[N.Y]N=[N²[Nao[NA [NAA[NAAF]NAI[NASL[NB[NC[ND[NEA[NEH[NES [NF[NG[NH[NI[NIC]NIL]NIM]NIMH[NIN]NIS]NJC[NK[NL[NLS]NM[NNR[NNT[NP[NPO]NPOV-[NR[NRJ]NRT]NS[NSW]NT[NT$]NUS[NV[Nv[NWA[NX[NYP[NYU[n-[n−[n [n\"[n&[n,[n+[n×[nda[npa[nt[nV[nW[o[obr]occurs]ocho]of ]on]on-[on/[onb[onco[ond[oner[ong[oni[onl[onm[ono[onr[ons[ont[onu[onw[ony[or ]or,]oui]O[Obers]Oberst [Oberstl[Olv]One]Onei[ONE]Oop]Oui]Ó[Ö[ö[Ō[ō[Phob[Phoi[r'[r-[r [r\"[r&[r.[refers[rf[rm[rs[R1[R10]R2[R3[R4[R5[R6[R'[R-[R [R\"[R&[R,[R.[R.C]R/[RA [RAF[RB[RC[RD[RE [RER[RF[Rf[RG[RHS[RIA[RIC [RJ[RK[RL[RL ]RM[RM1]RN[RNG]ROT[RP[RQ[RR[RS[RS ]RS)]RS,]RS.]RS?]RST]RT[RU[RV[RX[s-[s\"[s)[s,[s.[says[sich[sp3[sprot[ssh[states [states:[sv[sva]sve]S1[S2[S3[S4[S5[S6[S'[S-[S [S\"[S&[S&W]S,[S.B[S.M[S.O[S”[SA-[SA-1]SA [SACD[SAE[SAS[SASE]SAT [SATB[SB[SCA [SCC[SCM[SCO [SCR[SCRA]SCT[SD[SE [SEC[SECO]SECR]SEI[SEO[SF[SG[SH2[SH3[SH-[SI [SJ[SK[SL[SLA]SLI]SLO]SM[SMA]SME]SME [SMI]SN[SNA]SNE]SNO]SO([SOA [SOAI[SOE[SOI[SOS[SOV[SP[SPAC]SPAD]SPAM]SPAN]SPAR]SPE]SPE [SPIC]SPO]SPU]SR[SS[ST-[STA [STB[STC[STD[STF[STL[STM[STS[STV[Sura [SU[SUB]SUL]SUN]SUP]SUS]SV[SWF[SWP[SWR[SX[SXS]t-S[than [tS[Taves[Tà[u[u-]u ]u\"]u.]ub]ube[uf]uk]uka[ulu]um ]un ]una ]unan]unana[unann[unans[unant[unary]une ]uni]unicorp[unid[unidi]unim[unimo]unin[unintentionall]unintentionally [univo[unles]until ]upo]ura]ure]uri]url]uro]us]us-[us [ush[ut]utm[utt[uv]uw]U1[U-21[U-23 [U-B[U-Bo]Ua[Ub[Ubi]UDP-[Ud[Ugl[Uh[Ui[Ul[Uli]Um[UMN[Un-[Una[Unan]Unb[Unc[Und[Une[Unes]Unf[Ung[Unh[Unid[Unin[Unk[Unl[Unm[Unn[Uno[Unp[Unr[Uns[Unt[Unters]Unu[Unw[Up[Ur[Ura]Uri]Uru]Uruguayan-[Uruk[Ush[Ust[Utn[Uto-[Utr[Utt[Ux[Uz[ü[Ü[verses[Valley,[VII[WikiEl[x[xa]xe]xi]xo]xx]xy]X[Xa]XA]Xe]Xh]Xi]Xiany[XIV]XIX]Xo]Xu]XU]XV]XX]XX [Xy]Yp[Zen)[α[ε[ω[西[長["
13
+
14
+ @root = {}
15
+ DICT.gsub /([^\[\]]*)([\[\]])/ do |match|
16
+ m = /([^\[\]]*)([\[\]])/.match match
17
+ prefix = m[1]
18
+ aVsAn = m[2] # a is closing bracket, an is opening.
19
+ node = @root
20
+ prefix.each_char do |letter|
21
+ node[letter] ||= {}
22
+ node = node[letter]
23
+ end
24
+
25
+ node[:article] = aVsAn == "]" ? "a" : "an"
26
+ end
27
+
28
+ def self.for(word)
29
+ node = @root
30
+ article = node[:article]
31
+ sI = 0
32
+
33
+ while true
34
+ if sI >= word.size
35
+ return article
36
+ elsif word[sI] === "(" || word[sI] === "'" || word[sI] === '"'
37
+ sI += 1
38
+ else
39
+ break
40
+ end
41
+ end
42
+
43
+ while true
44
+ node = node[word[sI]];
45
+ break unless node
46
+ article = node[:article] if node[:article]
47
+
48
+ sI += 1
49
+ if sI >= word.length
50
+ node = node[" "]
51
+ article = node[:article] if node && node[:article]
52
+ break
53
+ end
54
+ end
55
+
56
+ article.dup
57
+ end
58
+
59
+ def self.correct_sentence(initial_sentence)
60
+ initial_sentence.gsub /\b(a|an|A|An)\b(\s)+\b([\w']+)\b/ do |s|
61
+ article, space, word = s.split /\b/
62
+ new_article = self.for word
63
+ new_article.capitalize! if article[0] == 'A'
64
+
65
+ "#{new_article}#{space}#{word}"
66
+ end
67
+ end
68
+ end
69
+
70
+ end
@@ -0,0 +1,94 @@
1
+ module ShouldaMatchmakers
2
+ module Model
3
+ module ActiveRecord
4
+ module ActiveRecordMatcher
5
+ module BelongTo
6
+
7
+ def belong_to_matcher_tests
8
+ belong_to_tests = []
9
+ @active_record_model_sm_model.constantize.reflect_on_all_associations(:belongs_to).map{ |belong_to| { :association_class_name=>belong_to.name, :association_options=>belong_to.options } }.map do |association|
10
+ association_class_name = association[:association_class_name].to_s
11
+ association_options = association[:association_options]
12
+ belong_to_test = generate_belong_to_test_single_line(association_class_name, association_options)
13
+ if belong_to_test[0].length > 80 || association_options.count > 1
14
+ belong_to_test = generate_belong_to_test_multiple_lines(association_class_name, association_options)
15
+ end
16
+ belong_to_tests << belong_to_test
17
+ end
18
+ belong_to_tests.flatten.compact.uniq.join("\n\n")
19
+ end
20
+
21
+
22
+ private
23
+
24
+ def generate_belong_to_test_single_line(association_class_name, association_options)
25
+ belong_to_test = " it { is_expected.to belong_to(:#{ association_class_name })"
26
+ association_options.map do |option, option_value|
27
+ belong_to_test_option = get_belong_to_test_option(option, option_value)
28
+ belong_to_test.concat("." + belong_to_test_option) if belong_to_test_option.present?
29
+ end
30
+ belong_to_test.concat(" }")
31
+ [belong_to_test]
32
+ end
33
+
34
+
35
+ def generate_belong_to_test_multiple_lines(association_class_name, association_options)
36
+ belong_to_test = " it do\n is_expected.to belong_to(:#{ association_class_name })"
37
+ belong_to_test_options = get_belong_to_test_options(association_options)
38
+ belong_to_test.concat(belong_to_test_options) if belong_to_test_options.present?
39
+ belong_to_test.concat("\n end")
40
+ [belong_to_test]
41
+ end
42
+
43
+
44
+ def get_belong_to_test_options(association_options)
45
+ belong_to_test_options = ""
46
+ association_options.map do |option, option_value|
47
+ belong_to_test_option = get_belong_to_test_option(option, option_value)
48
+ belong_to_test_options.concat(".\n " + belong_to_test_option) if belong_to_test_option.present?
49
+ end
50
+ belong_to_test_options
51
+ end
52
+
53
+
54
+ def get_belong_to_test_option(option, option_value)
55
+ # IMPLEMENTATION TODO: Determine if it is possible to implement 'conditions'
56
+ case option
57
+ when :autosave
58
+ "autosave(#{ option_value })"
59
+ when :class_name
60
+ "class_name('#{ option_value }')"
61
+ when :counter_cache
62
+ "counter_cache(#{ option_value })"
63
+ when :dependent
64
+ if option_value.to_s == "true" or option_value.to_s == "false"
65
+ "dependent(#{ option_value })"
66
+ else
67
+ "dependent(:#{ option_value })"
68
+ end
69
+ when :foreign_key
70
+ "with_foreign_key('#{ option_value }')"
71
+ when :inverse_of
72
+ "inverse_of(:#{ option_value })"
73
+ # # VERIFICATION TODO: Verify capture of 'order' value due to its unique syntax (e.g. '-> { order("priority desc")' })
74
+ when :order
75
+ if option_value.include? '"'
76
+ "order('#{ option_value }')"
77
+ else
78
+ "order(\"#{ option_value }\")"
79
+ end
80
+ when :primary_key
81
+ "with_primary_key('#{ option_value }')"
82
+ when :touch
83
+ "touch(#{ option_value })"
84
+ else
85
+ # IMPLEMENTATION TODO: Possibly handle this case option as an error or modify evaluation of option (see TODO above)
86
+ ""
87
+ end
88
+ end
89
+
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,83 @@
1
+ module ShouldaMatchmakers
2
+ module Model
3
+ module ActiveRecord
4
+ module ActiveRecordMatcher
5
+ module HaveAndBelongToMany
6
+
7
+
8
+ def have_and_belong_to_many_matcher_tests
9
+ habtm_tests = []
10
+ @active_record_model_sm_model.constantize.reflect_on_all_associations(:has_and_belongs_to_many).map{ |habtm| { :association_class_name=>habtm.name, :association_options=>habtm.options } }.map do |association|
11
+ association_class_name = association[:association_class_name].to_s
12
+ association_options = association[:association_options]
13
+ habtm_test = generate_habtm_test_single_line(association_class_name, association_options)
14
+ if habtm_test[0].length > 80 || association_options.count > 1
15
+ habtm_test = generate_habtm_test_multiple_lines(association_class_name, association_options)
16
+ end
17
+ habtm_tests << habtm_test
18
+ end
19
+ habtm_tests.flatten.compact.uniq.join("\n\n")
20
+ end
21
+
22
+
23
+ private
24
+
25
+ def generate_habtm_test_single_line(association_class_name, association_options)
26
+ habtm_test = " it { is_expected.to have_and_belong_to_many(:#{ association_class_name })"
27
+ association_options.map do |option, option_value|
28
+ habtm_test_option = get_habtm_test_option(option, option_value)
29
+ habtm_test.concat("." + habtm_test_option) if habtm_test_option.present?
30
+ end
31
+ habtm_test.concat(" }")
32
+ [habtm_test]
33
+ end
34
+
35
+
36
+ def generate_habtm_test_multiple_lines(association_class_name, association_options)
37
+ habtm_test = " it do\n is_expected.to have_and_belong_to_many(:#{ association_class_name })"
38
+ habtm_test_options = get_habtm_test_options(association_options)
39
+ habtm_test.concat(habtm_test_options) if habtm_test_options.present?
40
+ habtm_test.concat("\n end")
41
+ [habtm_test]
42
+ end
43
+
44
+
45
+ def get_habtm_test_options(association_options)
46
+ habtm_test_options = ""
47
+ association_options.map do |option, option_value|
48
+ habtm_test_option = get_habtm_test_option(option, option_value)
49
+ habtm_test_options.concat(".\n " + habtm_test_option) if habtm_test_option.present?
50
+ end
51
+ habtm_test_options
52
+ end
53
+
54
+
55
+ def get_habtm_test_option(option, option_value)
56
+ # IMPLEMENTATION TODO: Determine if it is possible to implement 'conditions'
57
+ case option
58
+ when :autosave
59
+ "autosave(#{ option_value })"
60
+ when :class_name
61
+ "class_name('#{ option_value }')"
62
+ when :join_table
63
+ "join_table('#{ option_value }')"
64
+ # VERIFICATION TODO: Verify capture of 'order' value due to its unique syntax (e.g. '-> { order("priority desc")' })
65
+ when :order
66
+ if option_value.include? '"'
67
+ "order('#{ option_value }')"
68
+ else
69
+ "order(\"#{ option_value }\")"
70
+ end
71
+ when :validate
72
+ "validate(#{ option_value })"
73
+ else
74
+ # IMPLEMENTATION TODO: Possibly handle this case option as an error or modify evaluation of option (see TODO above)
75
+ ""
76
+ end
77
+ end
78
+
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,96 @@
1
+ module ShouldaMatchmakers
2
+ module Model
3
+ module ActiveRecord
4
+ module ActiveRecordMatcher
5
+ module HaveMany
6
+
7
+ def have_many_matcher_tests
8
+ have_many_tests = []
9
+ @active_record_model_sm_model.constantize.reflect_on_all_associations(:has_many).map{ |have_many| { :association_class_name=>have_many.name, :association_options=>have_many.options } }.map do |association|
10
+ association_class_name = association[:association_class_name].to_s
11
+ association_options = association[:association_options]
12
+ have_many_test = generate_have_many_test_single_line(association_class_name, association_options)
13
+ if have_many_test[0].length > 80 || association_options.count > 1
14
+ have_many_test = generate_have_many_test_multiple_lines(association_class_name, association_options)
15
+ end
16
+ have_many_tests << have_many_test
17
+ end
18
+ have_many_tests.flatten.compact.uniq.join("\n\n")
19
+ end
20
+
21
+
22
+ private
23
+
24
+ def generate_have_many_test_single_line(association_class_name, association_options)
25
+ have_many_test = " it { is_expected.to have_many(:#{ association_class_name })"
26
+ association_options.map do |option, option_value|
27
+ have_many_test_option = get_have_many_test_option(option, option_value)
28
+ have_many_test.concat("." + have_many_test_option) if have_many_test_option.present?
29
+ end
30
+ have_many_test.concat(" }")
31
+ [have_many_test]
32
+ end
33
+
34
+
35
+ def generate_have_many_test_multiple_lines(association_class_name, association_options)
36
+ have_many_test = " it do\n is_expected.to have_many(:#{ association_class_name })"
37
+ have_many_test_options = get_have_many_test_options(association_options)
38
+ have_many_test.concat(have_many_test_options) if have_many_test_options.present?
39
+ have_many_test.concat("\n end")
40
+ [have_many_test]
41
+ end
42
+
43
+
44
+ def get_have_many_test_options(association_options)
45
+ have_many_test_options = ""
46
+ association_options.map do |option, option_value|
47
+ have_many_test_option = get_have_many_test_option(option, option_value)
48
+ have_many_test_options.concat(".\n " + have_many_test_option) if have_many_test_option.present?
49
+ end
50
+ have_many_test_options
51
+ end
52
+
53
+
54
+ def get_have_many_test_option(option, option_value)
55
+ # IMPLEMENTATION TODO: Determine if it is possible to implement 'conditions'
56
+ case option
57
+ when :autosave
58
+ "autosave(#{ option_value })"
59
+ when :class_name
60
+ "class_name('#{ option_value }')"
61
+ when :dependent
62
+ if option_value.to_s == "true" or option_value.to_s == "false"
63
+ "dependent(#{ option_value })"
64
+ else
65
+ "dependent(:#{ option_value })"
66
+ end
67
+ when :foreign_key
68
+ "with_foreign_key('#{ option_value }')"
69
+ when :inverse_of
70
+ "inverse_of(:#{ option_value })"
71
+ # VERIFICATION TODO: Verify capture of 'order' value due to its unique syntax (e.g. '-> { order("priority desc")' })
72
+ when :order
73
+ if option_value.include? '"'
74
+ "order('#{ option_value }')"
75
+ else
76
+ "order(\"#{ option_value }\")"
77
+ end
78
+ when :primary_key
79
+ "with_primary_key('#{ option_value }')"
80
+ when :source
81
+ "source(:#{ option_value })"
82
+ when :through
83
+ "through(:#{ option_value })"
84
+ when :validate
85
+ "validate(#{ option_value })"
86
+ else
87
+ # IMPLEMENTATION TODO: Possibly handle this case option as an error or modify evaluation of option (see TODO above)
88
+ ""
89
+ end
90
+ end
91
+
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,98 @@
1
+ module ShouldaMatchmakers
2
+ module Model
3
+ module ActiveRecord
4
+ module ActiveRecordMatcher
5
+ module HaveOne
6
+
7
+
8
+ def have_one_matcher_tests
9
+ have_one_tests = []
10
+ @active_record_model_sm_model.constantize.reflect_on_all_associations(:has_one).map{ |have_one| { :association_class_name=>have_one.name, :association_options=>have_one.options } }.map do |association|
11
+ association_class_name = association[:association_class_name].to_s
12
+ association_options = association[:association_options]
13
+ have_one_test = generate_have_one_test_single_line(association_class_name, association_options)
14
+ if have_one_test[0].length > 80 || association_options.count > 1
15
+ have_one_test = generate_have_one_test_multiple_lines(association_class_name, association_options)
16
+ end
17
+ have_one_tests << have_one_test
18
+ end
19
+ have_one_tests.flatten.compact.uniq.join("\n\n")
20
+ end
21
+
22
+
23
+ private
24
+
25
+ def generate_have_one_test_single_line(association_class_name, association_options)
26
+ have_one_test = " it { is_expected.to have_one(:#{ association_class_name })"
27
+ association_options.map do |option, option_value|
28
+ have_one_test_option = get_have_one_test_option(option, option_value)
29
+ have_one_test.concat("." + have_one_test_option) if have_one_test_option.present?
30
+ end
31
+ have_one_test.concat(" }")
32
+ [have_one_test]
33
+ end
34
+
35
+
36
+ def generate_have_one_test_multiple_lines(association_class_name, association_options)
37
+ have_one_test = " it do\n is_expected.to have_one(:#{ association_class_name })"
38
+ have_one_test_options = get_have_one_test_options(association_options)
39
+ have_one_test.concat(have_one_test_options) if have_one_test_options.present?
40
+ have_one_test.concat("\n end")
41
+ [have_one_test]
42
+ end
43
+
44
+
45
+ def get_have_one_test_options(association_options)
46
+ have_one_test_options = ""
47
+ association_options.map do |option, option_value|
48
+ have_one_test_option = get_have_one_test_option(option, option_value)
49
+ have_one_test_options.concat(".\n " + have_one_test_option) if have_one_test_option.present?
50
+ end
51
+ have_one_test_options
52
+ end
53
+
54
+
55
+ def get_have_one_test_option(option, option_value)
56
+ # IMPLEMENTATION TODO: Determine if it is possible to implement 'conditions'
57
+ case option
58
+ when :autosave
59
+ "autosave(#{ option_value })"
60
+ when :class_name
61
+ "class_name('#{ option_value }')"
62
+ when :dependent
63
+ if option_value.to_s == "true" or option_value.to_s == "false"
64
+ "dependent(#{ option_value })"
65
+ else
66
+ "dependent(:#{ option_value })"
67
+ end
68
+ when :foreign_key
69
+ "with_foreign_key('#{ option_value }')"
70
+ # IMPLEMENTATION TODO: Determine if Shoulda Matchers recognizes the 'inverse_of' option for 'have_one'
71
+ # when :inverse_of
72
+ # "inverse_of(:#{ option_value })"
73
+ # VERIFICATION TODO: Verify capture of 'order' value due to its unique syntax (e.g. '-> { order("priority desc")' })
74
+ when :order
75
+ if option_value.include? '"'
76
+ "order('#{ option_value }')"
77
+ else
78
+ "order(\"#{ option_value }\")"
79
+ end
80
+ when :primary_key
81
+ "with_primary_key('#{ option_value }')"
82
+ when :source
83
+ "source(:#{ option_value })"
84
+ when :through
85
+ "through(:#{ option_value })"
86
+ when :validate
87
+ "validate(#{ option_value })"
88
+ else
89
+ # IMPLEMENTATION TODO: Possibly handle this case option as an error or modify evaluation of option (see TODO above)
90
+ ""
91
+ end
92
+ end
93
+
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,270 @@
1
+ # LATEST REFACTOR =================================================================================
2
+
3
+ def get_action_permitted_params_entities(controller)
4
+ action_permitted_params_entities = []
5
+ controller_file_path = Rails.root.join("app", "controllers").to_s + "/" +
6
+ controller.to_s.gsub("::", "/").gsub(/.*[^\/]/) { |pc| pc.underscore }.concat(".rb").gsub("//", "/").to_s
7
+ if File.exists?(controller_file_path)
8
+ permitted_params_defs = gather_permitted_params_defs(controller_file_path, controller)
9
+ if permitted_params_defs.present?
10
+ action_permitted_params_entities = gather_action_permitted_params_entities(permitted_params_defs)
11
+ end
12
+ end
13
+ action_permitted_params_entities
14
+ end
15
+
16
+ def gather_permitted_params_defs(controller_file_path, controller)
17
+ controller_method = nil
18
+ parsing_params = false
19
+ permitted_params_def = nil
20
+ permitted_params_defs = []
21
+ File.open(controller_file_path, 'r') do |controller_file|
22
+ controller_file.each_line do |line|
23
+ if line =~ /\s+def\s[A-Za-z0-9_][A-Za-z0-9_!\?=]+/
24
+ controller_method = update_current_controller_method(line)
25
+ else
26
+ if line =~ /params\.require\(:/ && controller_method.present?
27
+ permitted_params_def = create_permitted_params_def(line, controller.to_s, controller_method)
28
+ end
29
+ if line =~ /permit\(/ && permitted_params_def.present? && permitted_params_def.params_class.present?
30
+ parsing_params = true
31
+ end
32
+ if parsing_params
33
+ permitted_params = get_permitted_params(line)
34
+ permitted_params_def.permitted_params << permitted_params if permitted_params.present?
35
+ if line =~ /end\s*\n/
36
+ permitted_params_def.permitted_params = permitted_params_def.permitted_params.flatten
37
+ permitted_params_defs << permitted_params_def
38
+ permitted_params_def = nil
39
+ controller_method = nil
40
+ parsing_params = false
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ permitted_params_defs
47
+ end
48
+
49
+ def update_current_controller_method(line)
50
+ line.scan(/\s+def\s([A-Za-z0-9_][A-Za-z0-9_!\?=]+)/).first.first
51
+ end
52
+
53
+ def create_permitted_params_def(line, controller, controller_method)
54
+ params_class = line.scan(/params\.require\((:[a-z][a-z0-9_]*)\)/).first.first
55
+ ::ShouldaMatchmakers::Controller::ActionController::PermittedParamsDefinition.new(controller.to_s, controller_method, params_class)
56
+ end
57
+
58
+ def get_permitted_params(line)
59
+ permitted_params = line.scan(/(:[a-z][a-z0-9_]*)[,\s\)]/)
60
+ if line =~ /params\.require\(:/
61
+ permitted_params.shift
62
+ end
63
+ permitted_params.flatten.compact.uniq
64
+ end
65
+
66
+ def gather_action_permitted_params_entities(permitted_params_defs)
67
+ action_permitted_params_entities = []
68
+ controller_method = nil
69
+ permitted_params_defs.each do |permitted_params_def|
70
+ controller_file.each_line do |line|
71
+ if line =~ /\s+def\s[A-Za-z0-9_][A-Za-z0-9_!\?=]+/
72
+ controller_method = update_current_controller_method(line)
73
+ else
74
+ if line.include?("(" + permitted_params_def.defining_method + ")")
75
+ action_permitted_params_entity = create_action_permitted_params_entity(line, permitted_params_def, controller_method)
76
+ if action_permitted_params_entity.params_class_controller_action.present?
77
+ action_permitted_params_entity.params_class_controller_action = action_permitted_params_entity.params_class_controller_action.first
78
+ action_permitted_params_entities << action_permitted_params_entity
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ action_permitted_params_entities
85
+ end
86
+
87
+ def create_action_permitted_params_entity(line, permitted_params_def, controller_method)
88
+ action_permitted_params_entity = permitted_params_def.dup
89
+ action_permitted_params_entity.calling_method = controller_method
90
+ action_permitted_params_entity.params_class_controller_action =
91
+ line.scan(/\s[A-Za-z@][A-Za-z0-9_]*\.([a-z]+)\(#{permitted_params_def.defining_method}\)/).first
92
+ action_permitted_params_entity
93
+ end
94
+
95
+ # =================================================================================================
96
+
97
+
98
+
99
+ # FIRST REFACTOR ==================================================================================
100
+
101
+ def get_action_permitted_params_entities(controller)
102
+ controller_file_path = Rails.root.join("app", "controllers").to_s + "/" +
103
+ controller.to_s.gsub("::", "/").gsub(/.*[^\/]/) { |pc| pc.underscore }.concat(".rb").gsub("//", "/").to_s
104
+ action_permitted_params_entities = []
105
+ if File.exists?(controller_file_path)
106
+ permitted_params_defs = gather_permitted_params_defs(controller_file_path, controller)
107
+ action_permitted_params_entities = part_two(controller_file_path, permitted_params_defs) if permitted_params_defs.present?
108
+ end
109
+ action_permitted_params_entities
110
+ end
111
+
112
+ def gather_permitted_params_defs(controller_file_path, controller)
113
+ permitted_params_defs = []
114
+ parsing_params = false
115
+ controller_method = nil
116
+ File.open(controller_file_path, 'r') do |controller_file|
117
+ controller_file.each_line do |line|
118
+ if line =~ /\s+def\s[A-Za-z0-9_][A-Za-z0-9_!\?=]+/
119
+ controller_method = line.scan(/\s+def\s([A-Za-z0-9_][A-Za-z0-9_!\?=]+)/).first.first
120
+ else
121
+ permitted_params_defs << compose_permitted_params_def(line, controller, controller_method, parsing_params)
122
+ if parsing_params && line =~ /end\s*\n/
123
+ parsing_params = false
124
+ controller_method = nil
125
+ end
126
+ end
127
+ end
128
+ end
129
+ permitted_params_defs
130
+ end
131
+
132
+ def compose_permitted_params_def(line, controller, controller_method, parsing_params)
133
+ permitted_params_def = nil
134
+ if line =~ /params\.require\(:/ && controller_method.present?
135
+ permitted_params_def = create_permitted_params_def(line, controller, controller_method)
136
+ end
137
+ if line =~ /permit\(/ && permitted_params_def.present? && permitted_params_def.params_class.present?
138
+ parsing_params = true
139
+ end
140
+ if parsing_params
141
+ permitted_params = gather_permitted_params(line)
142
+ permitted_params_def.permitted_params << permitted_params if permitted_params.present?
143
+ if line =~ /end\s*\n/
144
+ permitted_params_def.permitted_params = permitted_params_def.permitted_params.flatten
145
+ valid_permitted_params_def = permitted_params_def
146
+ permitted_params_def = nil
147
+ end
148
+ end
149
+ valid_permitted_params_def
150
+ end
151
+
152
+ def create_permitted_params_def(line, controller, controller_method)
153
+ params_class = line.scan(/params\.require\((:[a-z][a-z0-9_]*)\)/).first.first
154
+ ::ShouldaMatchmakers::Controller::ActionController::PermittedParamsDefinition.new(controller.to_s, controller_method, params_class)
155
+ end
156
+
157
+ def gather_permitted_params(line)
158
+ permitted_params = line.scan(/(:[a-z][a-z0-9_]*)[,\s\)]/)
159
+ if line =~ /params\.require\(:/
160
+ permitted_params.shift
161
+ end
162
+ permitted_params.flatten.compact.uniq
163
+ end
164
+
165
+ def gather_get_action_permitted_params_entities(controller_file_path, permitted_params_defs)
166
+ action_permitted_params_entities = []
167
+ controller_method = ""
168
+ File.open(controller_file_path, 'r') do |controller_file|
169
+ permitted_params_defs.each do |permitted_params_def|
170
+ controller_file.each_line do |line|
171
+ if line =~ /\s+def\s[A-Za-z0-9_][A-Za-z0-9_!\?=]+/
172
+ controller_method = line.scan(/\s+def\s([A-Za-z0-9_][A-Za-z0-9_!\?=]+)/).first.first
173
+ else
174
+ action_permitted_params_entity = create_action_permitted_params_entity(line, permitted_params_def, controller_method)
175
+ action_permitted_params_entities << action_permitted_params_entity if action_permitted_params_entity.present?
176
+ end
177
+ end
178
+ end
179
+ end
180
+ action_permitted_params_entities
181
+ end
182
+
183
+ def create_action_permitted_params_entity(line, permitted_params_def, controller_method)
184
+ action_permitted_params_entity = nil
185
+ if line.include?("(" + permitted_params_def.defining_method + ")")
186
+ action_permitted_params_entity = permitted_params_def.dup
187
+ action_permitted_params_entity.calling_method = controller_method
188
+ action_permitted_params_entity.params_class_controller_action =
189
+ line.scan(/\s[A-Za-z@][A-Za-z0-9_]*\.([a-z]+)\(#{permitted_params_def.defining_method}\)/).first
190
+ if action_permitted_params_entity.params_class_controller_action.present?
191
+ action_permitted_params_entity.params_class_controller_action = action_permitted_params_entity.params_class_controller_action.first
192
+ else
193
+ action_permitted_params_entity = nil
194
+ end
195
+ end
196
+ action_permitted_params_entity
197
+ end
198
+
199
+ # =================================================================================================
200
+
201
+
202
+
203
+ # ORIGINAL ========================================================================================
204
+
205
+ def get_action_permitted_params_entities_original(controller)
206
+ controller_file_path = Rails.root.join("app", "controllers").to_s + "/" +
207
+ controller.to_s.gsub("::", "/").gsub(/.*[^\/]/) { |pc| pc.underscore }.concat(".rb").gsub("//", "/").to_s
208
+
209
+ action_permitted_params_entities = []
210
+ permitted_params_defs = []
211
+ permitted_params_def = nil
212
+ controller_method = nil
213
+ parsing_params = false
214
+
215
+ if File.exists?(controller_file_path)
216
+ File.open(controller_file_path, 'r') do |controller_file|
217
+ controller_file.each_line do |line|
218
+ if line =~ /\s+def\s[A-Za-z0-9_][A-Za-z0-9_!\?=]+/
219
+ controller_method = line.scan(/\s+def\s([A-Za-z0-9_][A-Za-z0-9_!\?=]+)/).first.first
220
+ else
221
+ if line =~ /params\.require\(:/ && controller_method.present?
222
+ params_class = line.scan(/params\.require\((:[a-z][a-z0-9_]*)\)/).first.first
223
+ permitted_params_def = ::ShouldaMatchmakers::Controller::ActionController::PermittedParamsDefinition.new(controller.to_s, controller_method, params_class)
224
+ end
225
+ if line =~ /permit\(/ && permitted_params_def.present? && permitted_params_def.params_class.present?
226
+ parsing_params = true
227
+ end
228
+ if parsing_params
229
+ permitted_params = line.scan(/(:[a-z][a-z0-9_]*)[,\s\)]/)
230
+ if line =~ /params\.require\(:/
231
+ permitted_params.shift
232
+ end
233
+ permitted_params = permitted_params.flatten.compact.uniq
234
+ permitted_params_def.permitted_params << permitted_params if permitted_params.present?
235
+ if line =~ /end\s*\n/
236
+ permitted_params_def.permitted_params = permitted_params_def.permitted_params.flatten
237
+ permitted_params_defs << permitted_params_def
238
+ permitted_params_def = nil
239
+ controller_method = nil
240
+ parsing_params = false
241
+ end
242
+ end
243
+ end
244
+ end
245
+ end
246
+
247
+
248
+ File.open(controller_file_path, 'r') do |controller_file|
249
+ permitted_params_defs.each do |pp_def|
250
+ controller_file.each_line do |line|
251
+ if line =~ /\s+def\s[A-Za-z0-9_][A-Za-z0-9_!\?=]+/
252
+ controller_method = line.scan(/\s+def\s([A-Za-z0-9_][A-Za-z0-9_!\?=]+)/).first.first
253
+ else
254
+ if line.include?("(" + pp_def.defining_method + ")")
255
+ action_permitted_params_entity = pp_def.dup
256
+ action_permitted_params_entity.calling_method = controller_method
257
+ action_permitted_params_entity.params_class_controller_action =
258
+ line.scan(/\s[A-Za-z@][A-Za-z0-9_]*\.([a-z]+)\(#{pp_def.defining_method}\)/).first
259
+ if action_permitted_params_entity.params_class_controller_action.present?
260
+ action_permitted_params_entity.params_class_controller_action = action_permitted_params_entity.params_class_controller_action.first
261
+ action_permitted_params_entities << action_permitted_params_entity
262
+ end
263
+ end
264
+ end
265
+ end
266
+ end
267
+ end
268
+ end
269
+ action_permitted_params_entities
270
+ end