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,126 @@
1
+ module ShouldaMatchmakers
2
+ module Controller
3
+ module ActionController
4
+ module Matchmaker
5
+ module RedirectTo
6
+
7
+
8
+ def redirect_to_matcher_tests
9
+ redirect_to_occurrences = get_redirect_to_occurrences(@app_controller_name)
10
+ if redirect_to_occurrences.present?
11
+ generate_redirect_to_matcher_tests(@app_controller_name, redirect_to_occurrences)
12
+ else
13
+ []
14
+ end
15
+ end
16
+
17
+
18
+ private
19
+
20
+ def get_redirect_to_occurrences(app_controller_name)
21
+ redirect_to_occurrences = []
22
+ app_controller_file_path = compose_extended_app_controller_file_path(app_controller_name)
23
+ if File.exists?(app_controller_file_path)
24
+ redirect_to_occurrences = parse_app_controller_for_redirect_to_occurrences(app_controller_file_path)
25
+ end
26
+ redirect_to_occurrences
27
+ end
28
+
29
+ def parse_app_controller_for_redirect_to_occurrences(app_controller_file_path)
30
+ redirect_to_occurrences = []
31
+ File.open(app_controller_file_path, 'r') do |app_controller_file|
32
+ current_app_controller_method = nil
33
+ continued_from_previous_line = false
34
+ app_controller_file.each_line do |app_controller_file_line|
35
+ if continued_from_previous_line
36
+ redirect_location = app_controller_file_line.scan(/^\s+(:?[a-z0-9_]+)/).flatten.first
37
+ if current_app_controller_method.present? && redirect_location.present?
38
+ redirect_to_occurrences << { controller_action: current_app_controller_method, redirect_location: redirect_location }
39
+ end
40
+ continued_from_previous_line = false
41
+ elsif app_controller_file_line =~ /\s+def\s[A-Za-z0-9_][A-Za-z0-9_!\?=]+/
42
+ current_app_controller_method = app_controller_file_line.scan(/\s+def\s([A-Za-z0-9_][A-Za-z0-9_!\?=]+)/).flatten.first
43
+ elsif app_controller_file_line =~ /^\s+redirect_to(?:\s+|\s*\()\s*:?[a-z0-9_]+/
44
+ redirect_location = app_controller_file_line.scan(/^\s+redirect_to(?:\s+|\s*\()\s*(:?[a-z0-9_]+)/).flatten.first
45
+ if current_app_controller_method.present? && redirect_location.present?
46
+ redirect_to_occurrences << { controller_action: current_app_controller_method, redirect_location: redirect_location }
47
+ end
48
+ elsif app_controller_file_line =~ /^\s+redirect_to(?:\s+|\s*\()\s*\n/
49
+ continued_from_previous_line = true
50
+ end
51
+ end
52
+ end
53
+ redirect_to_occurrences
54
+ end
55
+
56
+ def generate_redirect_to_matcher_tests(app_controller_name, redirect_to_occurrences)
57
+ redirect_to_tests = []
58
+ app_controller_route_controller = compose_route_controller(app_controller_name)
59
+ redirect_to_occurrences.each do |redirect_to_occurrence|
60
+ app_controller_action_routes = get_app_controller_routes_by_action(app_controller_route_controller, redirect_to_occurrence[:controller_action])
61
+ app_controller_action_routes.each do |app_controller_action_route|
62
+ redirect_to_test = generate_redirect_to_test(app_controller_route_controller, app_controller_action_route, redirect_to_occurrence)
63
+ redirect_to_tests = append_element(redirect_to_test, redirect_to_tests)
64
+ end
65
+ end
66
+ format_tests(redirect_to_tests)
67
+ end
68
+
69
+ def generate_redirect_to_test(app_controller_route_controller, app_controller_action_route, redirect_to_occurrence)
70
+ if redirect_to_occurrence[:redirect_location] =~ /^:/
71
+ redirect_to_action_and_path_hash = compose_redirect_to_action_and_path_hash_for_action(app_controller_route_controller, redirect_to_occurrence[:redirect_location])
72
+ elsif redirect_to_occurrence[:redirect_location] =~ /_path$/
73
+ redirect_to_action_and_path_hash = compose_redirect_to_action_and_path_hash_for_path(app_controller_action_route, redirect_to_occurrence[:redirect_location])
74
+ else
75
+ redirect_to_action_and_path_hash = { action: "", path: "" }
76
+ end
77
+ if redirect_to_action_and_path_hash[:action].present? || redirect_to_action_and_path_hash[:path].present?
78
+ compose_redirect_to_test(app_controller_action_route, redirect_to_action_and_path_hash)
79
+ else
80
+ ""
81
+ end
82
+ end
83
+
84
+ def compose_redirect_to_action_and_path_hash_for_action(app_controller_route_controller, redirect_location)
85
+ redirect_to_action_and_path_hash = {}
86
+ redirect_routes = get_app_controller_routes_by_action(app_controller_route_controller, redirect_location)
87
+ redirect_to_action_and_path_hash[:action] = redirect_location
88
+ if redirect_routes.present? && redirect_routes.first.name.present?
89
+ redirect_to_action_and_path_hash[:path] = redirect_routes.first.name.concat("_path")
90
+ else
91
+ redirect_to_action_and_path_hash[:path] = ""
92
+ end
93
+ redirect_to_action_and_path_hash
94
+ end
95
+
96
+ def compose_redirect_to_action_and_path_hash_for_path(app_controller_action_route, redirect_location)
97
+ redirect_to_action_and_path_hash = {}
98
+ redirect_routes = get_app_controller_routes_by_path(redirect_location)
99
+ if redirect_routes.present? && redirect_routes.first.defaults[:controller] == app_controller_action_route.defaults[:controller]
100
+ redirect_to_action_and_path_hash[:action] = redirect_routes.first.defaults[:action]
101
+ else
102
+ redirect_to_action_and_path_hash[:action] = ""
103
+ end
104
+ redirect_to_action_and_path_hash[:path] = redirect_location
105
+ redirect_to_action_and_path_hash
106
+ end
107
+
108
+ def compose_redirect_to_test(app_controller_action_route, redirect_to_action_and_path_hash)
109
+ app_controller_route_http_method = get_route_http_method(app_controller_action_route)
110
+ app_controller_action = app_controller_action_route.defaults[:action].to_s
111
+ redirect_to_test = " describe '#{ app_controller_route_http_method } ##{ app_controller_action }' do\n"
112
+ redirect_to_test.concat(" before { #{ app_controller_route_http_method.downcase } :#{ app_controller_action } }\n\n")
113
+ if redirect_to_action_and_path_hash[:path].present?
114
+ redirect_to_test.concat(" it { is_expected.to redirect_to(#{ redirect_to_action_and_path_hash[:path] }) }\n")
115
+ end
116
+ if redirect_to_action_and_path_hash[:action].present?
117
+ redirect_to_test.concat(" it { is_expected.to redirect_to(action: #{ redirect_to_action_and_path_hash[:action] }) }\n")
118
+ end
119
+ redirect_to_test.concat(" end\n")
120
+ end
121
+
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,198 @@
1
+ module ShouldaMatchmakers
2
+ module Controller
3
+ module ActionController
4
+ module Matchmaker
5
+ module RenderTemplate
6
+
7
+
8
+ def render_template_matcher_tests
9
+ render_template_occurrences = get_render_template_occurrences(@app_controller_name)
10
+ if render_template_occurrences.present?
11
+ generate_render_template_matcher_tests(render_template_occurrences)
12
+ else
13
+ []
14
+ end
15
+ end
16
+
17
+
18
+ private
19
+
20
+ def get_render_template_occurrences(app_controller_name)
21
+ render_template_occurrences = []
22
+ app_views_path = Rails.root.join("app", "views").to_s + "/"
23
+ app_controller_views_path = app_views_path + app_controller_name.underscore.sub(/_controller$/, "/")
24
+ %w(erb haml slim).each do |view_file_format|
25
+ render_template_occurrences = render_template_occurrences + get_render_template_occurrences_by_file_type(app_controller_name, app_views_path, app_controller_views_path, view_file_format)
26
+ end
27
+ render_template_occurrences
28
+ end
29
+
30
+ def get_render_template_occurrences_by_file_type(app_controller_name, app_views_path, app_controller_views_path, view_file_format)
31
+ render_template_occurrences_by_file_type = []
32
+ Dir.glob(app_controller_views_path + "**/*.html." + view_file_format) do |view_file_path|
33
+ view_action_render_occurrences = parse_controller_for_view_action_render_occurrences(view_file_path, app_views_path)
34
+ if view_action_render_occurrences.present?
35
+ view_action = get_view_from_path(view_file_path).sub(".html." + view_file_format, "")
36
+ if containing_method_is_action(app_controller_name, view_action)
37
+ render_template_occurrence_hashes = compose_render_template_occurrence_hashes(app_controller_name, view_action, view_action_render_occurrences)
38
+ render_template_occurrences_by_file_type = render_template_occurrences_by_file_type + render_template_occurrence_hashes
39
+ end
40
+ end
41
+ end
42
+ render_template_occurrences_by_file_type
43
+ end
44
+
45
+ def parse_controller_for_view_action_render_occurrences(view_file_path, app_views_path)
46
+ view_action_render_occurrences = []
47
+ File.open(view_file_path, 'r') do |view_file|
48
+ view_file.each_line do |view_file_line|
49
+ if view_file_line =~ /(?:\s+render|=render)(?:\s+action:\s+|\s+:action\s+=\>\s+|\s+file:\s+|\s+:file\s+=\>\s+|\s+partial:\s+|\s+:partial\s+=\>\s+|\s+template:\s+|\s+:template\s+=\>\s+|\s+)["':][A-Za-z0-9_\/\.]+"*'*\s*$/
50
+ view_action_render_occurrence = compose_view_action_render_occurrence_hash(app_views_path, view_file_path, view_file_line)
51
+ view_action_render_occurrences = append_element(view_action_render_occurrence, view_action_render_occurrences)
52
+ end
53
+ end
54
+ end
55
+ view_action_render_occurrences
56
+ end
57
+
58
+ def compose_view_action_render_occurrence_hash(app_views_path, view_file_path, view_file_line)
59
+ render_view_type, render_view_path = view_file_line.match(/(?:\s+render|=render)(\s+action:\s+|\s+:action\s+=\>\s+|\s+file:\s+|\s+:file\s+=\>\s+|\s+partial:\s+|\s+:partial\s+=\>\s+|\s+template:\s+|\s+:template\s+=\>\s+|\s+)["':]([A-Za-z0-9_\/\.]+)/).captures
60
+ if render_view_type.present?
61
+ render_view_type = render_view_type.gsub(/\s+/,"").gsub(":", "").gsub("=>","")
62
+ else
63
+ render_view_type = get_render_view_type(app_views_path, view_file_path, render_view_path)
64
+ end
65
+ { render_view_type: render_view_type, render_view: render_view_path }
66
+ end
67
+
68
+ def compose_render_template_occurrence_hashes(app_controller_name, view_action, view_action_render_occurrences)
69
+ render_template_occurrence_hashes = []
70
+ app_controller_routes_controller = compose_route_controller(app_controller_name)
71
+ view_action_routes = get_app_controller_routes_by_action(app_controller_routes_controller, view_action)
72
+ view_action_routes.each do |view_action_route|
73
+ view_action_http_method = get_route_http_method(view_action_route)
74
+ render_template_occurrence_hashes << { view_action: view_action, view_action_http_method: view_action_http_method, view_action_render_occurrences: view_action_render_occurrences }
75
+ end
76
+ render_template_occurrence_hashes
77
+ end
78
+
79
+ def generate_render_template_matcher_tests(render_template_occurrences)
80
+ render_template_tests = []
81
+ render_template_occurrences.sort_by!{ |rto| [rto[:view_action], rto[:view_action_http_method]] }
82
+ render_template_occurrences.each do |render_template_occurrence|
83
+ render_template_test = generate_render_template_test_initial(render_template_occurrence)
84
+ render_template_occurrence[:view_action_render_occurrences].sort_by!{ |varo| [varo[:render_view_type], varo[:render_view]] }
85
+ render_template_occurrence[:view_action_render_occurrences].each do |view_action_render_occurrence|
86
+ view_action_render_occurrence_test = generate_view_action_render_occurrence_test(view_action_render_occurrence)
87
+ render_template_test.concat(view_action_render_occurrence_test)
88
+ end
89
+ render_template_test.concat(" end")
90
+ render_template_tests = append_element(render_template_test, render_template_tests)
91
+ end
92
+ format_tests(render_template_tests)
93
+ end
94
+
95
+ def generate_render_template_test_initial(render_template_occurrence)
96
+ render_template_test = " describe '#{ render_template_occurrence[:view_action_http_method] } ##{ render_template_occurrence[:view_action] }' do\n"
97
+ render_template_test.concat(" before { #{ render_template_occurrence[:view_action_http_method].downcase } :#{ render_template_occurrence[:view_action] } }\n\n")
98
+ render_template_test.concat(" it { is_expected.to render_template('#{ render_template_occurrence[:view_action] }') }\n")
99
+ end
100
+
101
+ def generate_view_action_render_occurrence_test(view_action_render_occurrence)
102
+ if view_action_render_occurrence[:render_view_type] == "partial" && view_action_render_occurrence[:render_view].include?("/") ||
103
+ view_action_render_occurrence[:render_view_type] == "file"
104
+ view_action_render_occurrence_test = " it { is_expected.to render_template(#{ view_action_render_occurrence[:render_view_type] }: '"
105
+ elsif view_action_render_occurrence[:render_view_type] == "partial"
106
+ view_action_render_occurrence_test = " it { is_expected.to render_template(#{ view_action_render_occurrence[:render_view_type] }: '_"
107
+ elsif view_action_render_occurrence[:render_view_type] == "unknown"
108
+ view_action_render_occurrence_test = " # Unknown view type. Remove 'x' from 'xit' once view type identified (e.g. 'partial:', 'file:', etc.)\n"
109
+ view_action_render_occurrence_test.concat(" xit { is_expected.to render_template('")
110
+ else
111
+ view_action_render_occurrence_test = " it { is_expected.to render_template('"
112
+ end
113
+ view_action_render_occurrence_test.concat("#{ view_action_render_occurrence[:render_view] }') }\n")
114
+ end
115
+
116
+ def get_render_view_type(app_views_path, view_file_path, render_view_path)
117
+ render_view_and_directory = get_internal_render_view_and_directory(app_views_path, view_file_path, render_view_path)
118
+ render_view_type = identify_internal_render_view_type(render_view_and_directory, app_views_path)
119
+ if render_view_type == "unknown" && render_view_path.include?("/")
120
+ render_view_and_directory = get_external_render_view_and_directory(render_view_path)
121
+ render_view_type = identify_external_render_view_type(render_view_and_directory)
122
+ end
123
+ render_view_type
124
+ end
125
+
126
+ def get_internal_render_view_and_directory(app_views_path, view_file_path, render_view_path)
127
+ if render_view_path.include?("/")
128
+ render_view_directory = get_view_directory_prepended(render_view_path,app_views_path)
129
+ render_view = get_view_from_path(render_view_path).sub(/^\s*_/,"")
130
+ else
131
+ render_view_directory = get_view_directory_from_path(view_file_path)
132
+ render_view = render_view_path.sub(/^\s*_/,"")
133
+ end
134
+ { directory: render_view_directory, view: render_view }
135
+ end
136
+
137
+ def get_external_render_view_and_directory(render_view_path)
138
+ render_view_directory = get_view_directory_from_path(render_view_path)
139
+ render_view = get_view_from_path(render_view_path)
140
+ { directory: render_view_directory, view: render_view }
141
+ end
142
+
143
+ def get_view_from_path(view_path)
144
+ view_path.scan(/\/([a-zA-z0-9.]+)$/).last.first
145
+ end
146
+
147
+ def get_view_directory_from_path(view_path)
148
+ view_path.sub(/\/[a-zA-z0-9.]+$/,"/")
149
+ end
150
+
151
+ def get_view_directory_prepended(view_path, prepend_path)
152
+ view_path.sub(/\/[a-zA-z0-9.]+$/,"/").prepend(prepend_path)
153
+ end
154
+
155
+ def identify_internal_render_view_type(render_view_and_directory, app_views_path)
156
+ render_view_type = "unknown"
157
+ if view_partial_exist(render_view_and_directory)
158
+ render_view_type = "partial"
159
+ elsif view_exist(render_view_and_directory)
160
+ render_view_controller_name = get_controller_name_from_view_directory_path(render_view_and_directory[:directory], app_views_path)
161
+ if render_view_controller_name.present? && containing_method_is_action(render_view_controller_name, render_view_and_directory[:view])
162
+ render_view_type = "action"
163
+ else
164
+ render_view_type = "template"
165
+ end
166
+ end
167
+ render_view_type
168
+ end
169
+
170
+ def identify_external_render_view_type(render_view_and_directory)
171
+ render_view_type = "unknown"
172
+ if view_partial_exist(render_view_and_directory) || view_exist(render_view_and_directory)
173
+ render_view_type = "file"
174
+ end
175
+ render_view_type
176
+ end
177
+
178
+ def view_exist(render_view_and_directory)
179
+ File.exist?(render_view_and_directory[:directory] + render_view_and_directory[:view] + ".html.erb") ||
180
+ File.exist?(render_view_and_directory[:directory] + render_view_and_directory[:view] + ".html.haml") ||
181
+ File.exist?(render_view_and_directory[:directory] + render_view_and_directory[:view] + ".html.slim")
182
+ end
183
+
184
+ def view_partial_exist(render_view_and_directory)
185
+ File.exist?(render_view_and_directory[:directory] + "_" + render_view_and_directory[:view] + ".html.erb") ||
186
+ File.exist?(render_view_and_directory[:directory] + "_" + render_view_and_directory[:view] + ".html.haml") ||
187
+ File.exist?(render_view_and_directory[:directory] + "_" + render_view_and_directory[:view] + ".html.slim")
188
+ end
189
+
190
+ def get_controller_name_from_view_directory_path(view_directory_path, app_views_path)
191
+ view_directory_path.sub(app_views_path, "").sub(/\/$/,"").concat("_controller").camelize
192
+ end
193
+
194
+ end
195
+ end
196
+ end
197
+ end
198
+ end
@@ -0,0 +1,72 @@
1
+ module ShouldaMatchmakers
2
+ module Controller
3
+ module ActionController
4
+ module Matchmaker
5
+ module RenderWithLayout
6
+
7
+
8
+ def render_with_layout_matcher_tests
9
+ render_with_layout_occurrences = get_render_with_layout_occurrences(@app_controller_name)
10
+ if render_with_layout_occurrences.present?
11
+ generate_render_with_layout_matcher_tests(@app_controller_name, render_with_layout_occurrences)
12
+ else
13
+ []
14
+ end
15
+ end
16
+
17
+
18
+ private
19
+
20
+ def get_render_with_layout_occurrences(app_controller_name)
21
+ render_with_layout_occurrences = []
22
+ app_controller_file_path = compose_extended_app_controller_file_path(app_controller_name)
23
+ if File.exists?(app_controller_file_path)
24
+ render_with_layout_occurrences = parse_app_controller_for_render_with_layout_occurrences(app_controller_file_path)
25
+ end
26
+ render_with_layout_occurrences
27
+ end
28
+
29
+ def parse_app_controller_for_render_with_layout_occurrences(app_controller_file_path)
30
+ render_with_layout_occurrences = []
31
+ current_app_controller_method = nil
32
+ File.open(app_controller_file_path, 'r') do |app_controller_file|
33
+ app_controller_file.each_line do |app_controller_file_line|
34
+ if app_controller_file_line =~ /\s+def\s[A-Za-z0-9_][A-Za-z0-9_!\?=]+/
35
+ current_app_controller_method = app_controller_file_line.scan(/\s+def\s([A-Za-z0-9_][A-Za-z0-9_!\?=]+)/).flatten.first
36
+ elsif app_controller_file_line.include?(" render layout:")
37
+ render_with_layout_layout = app_controller_file_line.scan(/\s+render\slayout:\s['"]([a-z0-9_]+)/).flatten.first
38
+ if current_app_controller_method.present? && render_with_layout_layout.present?
39
+ render_with_layout_occurrences << { controller_action: current_app_controller_method, layout: render_with_layout_layout }
40
+ end
41
+ end
42
+ end
43
+ end
44
+ render_with_layout_occurrences
45
+ end
46
+
47
+ def generate_render_with_layout_matcher_tests(app_controller_name, render_with_layout_occurrences)
48
+ render_with_layout_tests = []
49
+ render_with_layout_occurrences.sort_by!{ |rwlo| [rwlo[:controller_action], rwlo[:layout]] }
50
+ render_with_layout_occurrences.each do |render_with_layout_occurrence|
51
+ app_controller_route_controller = compose_route_controller(app_controller_name)
52
+ app_controller_action_routes = get_app_controller_routes_by_action(app_controller_route_controller, render_with_layout_occurrence[:controller_action])
53
+ app_controller_action_routes.each do |app_controller_action_route|
54
+ render_with_layout_test = generate_render_with_layout_test(app_controller_action_route, render_with_layout_occurrence)
55
+ append_element(render_with_layout_test, render_with_layout_tests)
56
+ end
57
+ end
58
+ format_tests(render_with_layout_tests)
59
+ end
60
+
61
+ def generate_render_with_layout_test(app_controller_action_route, render_with_layout_occurrence)
62
+ app_controller_route_http_method = get_route_http_method(app_controller_action_route)
63
+ render_with_layout_test = " describe '#{ app_controller_route_http_method } ##{ render_with_layout_occurrence[:controller_action] }' do\n"
64
+ render_with_layout_test.concat(" before { #{ app_controller_route_http_method.downcase } :#{ render_with_layout_occurrence[:controller_action] } }\n\n")
65
+ render_with_layout_test.concat(" it { is_expected.to render_with_layout('#{ render_with_layout_occurrence[:layout] }') }\n end\n")
66
+ end
67
+
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,96 @@
1
+ module ShouldaMatchmakers
2
+ module Controller
3
+ module ActionController
4
+ module Matchmaker
5
+ module RescueFrom
6
+
7
+
8
+ def rescue_from_matcher_tests
9
+ rescue_from_occurrences = get_rescue_from_occurrences(@app_controller_name)
10
+ if rescue_from_occurrences.present?
11
+ generate_rescue_from_matcher_tests(rescue_from_occurrences)
12
+ else
13
+ []
14
+ end
15
+ end
16
+
17
+
18
+ private
19
+
20
+ def get_rescue_from_occurrences(app_controller_name)
21
+ rescue_from_occurrences = []
22
+ app_controller_file_path = compose_extended_app_controller_file_path(app_controller_name)
23
+ if File.exists?(app_controller_file_path)
24
+ rescue_from_occurrences = parse_app_controller_for_rescue_from_occurrences(app_controller_file_path)
25
+ end
26
+ rescue_from_occurrences
27
+ end
28
+
29
+ def parse_app_controller_for_rescue_from_occurrences(app_controller_file_path)
30
+ rescue_from_occurrences = []
31
+ rescue_from_occurrence = {}
32
+ continued_from_previous_line = false
33
+ File.open(app_controller_file_path, 'r') do |app_controller_file|
34
+ app_controller_file.each_line do |app_controller_file_line|
35
+ if continued_from_previous_line
36
+ if app_controller_file_line =~ /^\s*with:\s+[A-Za-z0-9:_]+\s*$/
37
+ rescue_from_handler = app_controller_file_line.scan(/^\s*with:\s+([A-Za-z0-9:_]+)/).flatten.first
38
+ rescue_from_occurrence[:handler] = rescue_from_handler
39
+ rescue_from_occurrences << rescue_from_occurrence
40
+ rescue_from_occurrence = {}
41
+ continued_from_previous_line = false
42
+ elsif !app_controller_file_line =~ /\s*\n/
43
+ rescue_from_occurrence[:handler] = ":unidentified_rescue_from_handler"
44
+ rescue_from_occurrences << rescue_from_occurrence
45
+ rescue_from_occurrence = {}
46
+ continued_from_previous_line = false
47
+ end
48
+ elsif app_controller_file_line =~ /^\s+rescue_from(?:\s+|\s*\()[A-Za-z0-9:]+\s*\)?,\s*with:\s+[A-Za-z0-9:_]+\s*$/
49
+ rescue_from_exception, rescue_from_handler = app_controller_file_line.match(/^\s+rescue_from(?:\s+|\s*\()([A-Za-z0-9:]+)\s*\)?,\s*with:\s+([A-Za-z0-9:_]+)/).captures
50
+ rescue_from_occurrence = { exception: rescue_from_exception, handler: rescue_from_handler }
51
+ rescue_from_occurrences << rescue_from_occurrence
52
+ rescue_from_occurrence = {}
53
+ continued_from_previous_line = false
54
+ elsif app_controller_file_line =~ /^\s+rescue_from(?:\s+|\s*\()[A-Za-z0-9:]+\s*\)?,\s*$/
55
+ rescue_from_exception = app_controller_file_line.scan(/^\s+rescue_from(?:\s+|\s*\()([A-Za-z0-9:]+)/).flatten.first
56
+ rescue_from_occurrence = { exception: rescue_from_exception }
57
+ continued_from_previous_line = true
58
+ elsif app_controller_file_line =~ /\s+rescue_from(?:\s+|\s*\()[A-Za-z0-9:]+\s*\)?/
59
+ rescue_from_exception = app_controller_file_line.scan(/^\s+rescue_from(?:\s+|\s*\()([A-Za-z0-9:]+)/).flatten.first
60
+ rescue_from_occurrence = { exception: rescue_from_exception, handler: ":unidentified_rescue_from_handler" }
61
+ rescue_from_occurrences << rescue_from_occurrence
62
+ rescue_from_occurrence = {}
63
+ continued_from_previous_line = false
64
+ end
65
+ end
66
+ end
67
+ rescue_from_occurrences
68
+ end
69
+
70
+ def generate_rescue_from_matcher_tests(rescue_from_occurrences)
71
+ rescue_from_tests = []
72
+ rescue_from_occurrences.each do |rescue_from_occurrence|
73
+ rescue_from_test = generate_rescue_from_test(rescue_from_occurrence)
74
+ rescue_from_tests = append_element(rescue_from_test, rescue_from_tests)
75
+ end
76
+ format_tests(rescue_from_tests)
77
+ end
78
+
79
+ def generate_rescue_from_test(rescue_from_occurrence)
80
+ if rescue_from_occurrence[:handler] == ":unidentified_rescue_from_handler"
81
+ rescue_from_test = "# A rescue_from occurrence contains complexities that make it difficult for ShouldaMatchmakers to parse completely.\n"
82
+ rescue_from_test.concat("# Examine the rescue_from occurrence for '#{ rescue_from_occurrence[:exception] }' to determine the appropriate\n")
83
+ rescue_from_test.concat("# syntax for the test and any required values, such as ':unidentified_rescue_from_handler' below.\n")
84
+ rescue_from_test.concat("# Remove 'x' from 'xit' once the proper syntax has been established and required values have been provided.\n")
85
+ rescue_from_test.concat(" xit do\n is_expected.to rescue_from(#{ rescue_from_occurrence[:exception] }).\n")
86
+ else
87
+ rescue_from_test = " it do\n is_expected.to rescue_from(#{ rescue_from_occurrence[:exception] }).\n"
88
+ end
89
+ rescue_from_test.concat(" with(#{ rescue_from_occurrence[:handler] })\n end\n")
90
+ end
91
+
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end