shoulda_matchmakers 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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