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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +21 -0
- data/lib/controller/action_controller/action_controller_controller_sm_model.rb +53 -0
- data/lib/controller/action_controller/action_controller_controller_sm_model_helper.rb +73 -0
- data/lib/controller/action_controller/matchmakers/callbacks.rb +56 -0
- data/lib/controller/action_controller/matchmakers/filter_param.rb +69 -0
- data/lib/controller/action_controller/matchmakers/permit.rb +510 -0
- data/lib/controller/action_controller/matchmakers/redirect_to.rb +126 -0
- data/lib/controller/action_controller/matchmakers/render_template.rb +198 -0
- data/lib/controller/action_controller/matchmakers/render_with_layout.rb +72 -0
- data/lib/controller/action_controller/matchmakers/rescue_from.rb +96 -0
- data/lib/controller/action_controller/matchmakers/respond_with.rb +71 -0
- data/lib/controller/action_controller/matchmakers/route.rb +586 -0
- data/lib/controller/action_controller/matchmakers/set_flash.rb +136 -0
- data/lib/controller/action_controller/matchmakers/set_session.rb +115 -0
- data/lib/controller/action_controller/permitted_params_definition.rb +60 -0
- data/lib/generators/shoulda_matchmakers/controller_matcher_generator.rb +87 -0
- data/lib/generators/shoulda_matchmakers/controller_matcher_generator_helper.rb +92 -0
- data/lib/generators/shoulda_matchmakers/factory_generator.rb +86 -0
- data/lib/generators/shoulda_matchmakers/install_generator.rb +10 -0
- data/lib/generators/shoulda_matchmakers/model_matcher_generator.rb +87 -0
- data/lib/generators/shoulda_matchmakers/model_matcher_generator_helper.rb +107 -0
- data/lib/model/active_record/active_record_model_sm_model.rb +50 -0
- data/lib/model/active_record/active_record_model_sm_model_helper.rb +206 -0
- data/lib/model/active_record/factory_sm_model.rb +28 -0
- data/lib/model/active_record/factory_sm_model_helper.rb +124 -0
- data/lib/model/active_record/matchmakers/accept_nested_attributes_for.rb +66 -0
- data/lib/model/active_record/matchmakers/allow_value.rb +137 -0
- data/lib/model/active_record/matchmakers/associations.rb +52 -0
- data/lib/model/active_record/matchmakers/define_enum_for.rb +53 -0
- data/lib/model/active_record/matchmakers/delegate_method.rb +101 -0
- data/lib/model/active_record/matchmakers/have_db_column.rb +33 -0
- data/lib/model/active_record/matchmakers/have_db_index.rb +39 -0
- data/lib/model/active_record/matchmakers/have_readonly_attribute.rb +32 -0
- data/lib/model/active_record/matchmakers/have_secure_password.rb +32 -0
- data/lib/model/active_record/matchmakers/serialize.rb +67 -0
- data/lib/model/active_record/matchmakers/validations.rb +169 -0
- data/lib/model/active_record/options_definition.rb +160 -0
- data/lib/shoulda_matchmakers.rb +48 -0
- data/lib/shoulda_matchmakers/version.rb +3 -0
- data/lib/support/command_line_interface.rb +100 -0
- data/lib/support/controller_generator.rb +198 -0
- data/lib/support/indefinite_article.rb +70 -0
- data/lib/support/to_discard/belong_to.rb +94 -0
- data/lib/support/to_discard/have_and_belong_to_many.rb +83 -0
- data/lib/support/to_discard/have_many.rb +96 -0
- data/lib/support/to_discard/have_one.rb +98 -0
- data/lib/support/to_discard/permit_refactor.rb +270 -0
- data/lib/support/to_discard/render_template_new.rb +204 -0
- data/lib/support/to_discard/render_template_reconstruction.rb +188 -0
- data/lib/support/to_discard/use_around_action.rb +20 -0
- data/lib/support/to_discard/use_before_action.rb +20 -0
- data/lib/support/to_discard/validate_absence_of.rb +16 -0
- data/lib/support/to_discard/validate_acceptance_of.rb +16 -0
- data/lib/support/to_discard/validate_confirmation_of.rb +16 -0
- data/lib/support/to_discard/validate_exclusion_of.rb +145 -0
- data/lib/support/to_discard/validate_inclusion_of.rb +94 -0
- data/lib/support/to_discard/validate_length_of.rb +16 -0
- data/lib/support/to_discard/validate_numericality_of.rb +16 -0
- data/lib/support/to_discard/validate_presence_of.rb +16 -0
- data/lib/support/to_discard/validate_uniqueness_of.rb +16 -0
- data/lib/support/to_discard/validation_old.rb +37 -0
- data/lib/support/to_discard/validations.rb +41 -0
- data/lib/support/to_discard/validations_conditional.rb +146 -0
- data/lib/support/trace_debug_lines.txt +319 -0
- data/lib/support/util.rb +15 -0
- data/lib/templates/controller/action_controller/controller_spec_template.haml +146 -0
- data/lib/templates/factory/active_record/factory_template.haml +13 -0
- data/lib/templates/model/active_record/model_spec_template.haml +233 -0
- data/lib/templates/shoulda_matchmakers.rb +112 -0
- metadata +263 -0
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'haml'
|
2
|
+
require_relative 'model_matcher_generator_helper'
|
3
|
+
require 'model/active_record/factory_sm_model'
|
4
|
+
require 'spin_to_win'
|
5
|
+
|
6
|
+
module ShouldaMatchmakers
|
7
|
+
class FactoryGenerator < ::Rails::Generators::Base
|
8
|
+
|
9
|
+
include Generator::ActiveRecord::ModelMatcherGeneratorHelper
|
10
|
+
|
11
|
+
source_root(File.expand_path(File.dirname(__FILE__)))
|
12
|
+
|
13
|
+
class_option :include, type: :array,
|
14
|
+
require: false,
|
15
|
+
aliases: '-i',
|
16
|
+
default: [],
|
17
|
+
desc: "Sets list of application ActiveRecord class names of models to INCLUDE in generated factories.\n" +
|
18
|
+
" By default, factories are generated for all ActiveRecord::Base descendant class models.\n" +
|
19
|
+
" When used, '_included' and '_excluded' settings in '~/config/initializers/shoulda_matchmakers.rb'\n" +
|
20
|
+
" configuration file are ignored. Example (space delimited, include namespaces):\n\n" +
|
21
|
+
" -i Driver License Vehicle::Car Vehicle::Bus\n\n\n"
|
22
|
+
|
23
|
+
class_option :exclude, type: :array,
|
24
|
+
require: false,
|
25
|
+
aliases: '-e',
|
26
|
+
default: [],
|
27
|
+
desc: "Sets list of application ActiveRecord class names of models to EXCLUDE from generated factories.\n" +
|
28
|
+
" By default, no ActiveRecord::Base descendant class models are excluded from generated factories.\n" +
|
29
|
+
" When used, '_included' and '_excluded' settings in '~/config/initializers/shoulda_matchmakers.rb'\n" +
|
30
|
+
" configuration file are ignored. Example (space delimited, include namespaces):\n\n" +
|
31
|
+
" -e Driver Vehicle::Car\n\n\n"
|
32
|
+
|
33
|
+
class_option :include_and_config, type: :array,
|
34
|
+
require: false,
|
35
|
+
aliases: '-I',
|
36
|
+
default: [],
|
37
|
+
desc: "Same as '-i/-include', except that '_included' and '_excluded' settings in\n" +
|
38
|
+
" '~/config/initializers/shoulda_matchmakers.rb' are not ignored. Configuration file\n" +
|
39
|
+
" settings are applied first then the class names listed with this option are applied.\n" +
|
40
|
+
" Example (space delimited, include namespaces):\n\n" +
|
41
|
+
" -I Driver License Vehicle::Car Vehicle::Bus\n\n\n"
|
42
|
+
|
43
|
+
class_option :exclude_and_config, type: :array,
|
44
|
+
require: false,
|
45
|
+
aliases: '-E',
|
46
|
+
default: [],
|
47
|
+
desc: "Same as '-e/-exclude', except that '_included' and '_excluded' settings in\n" +
|
48
|
+
" '~/config/initializers/shoulda_matchmakers.rb' are not ignored. Configuration file\n" +
|
49
|
+
" settings are applied first then the class names listed with this option are applied.\n" +
|
50
|
+
" Example (space delimited, include namespaces):\n\n" +
|
51
|
+
" -E Driver Vehicle::Car\n\n\n"
|
52
|
+
|
53
|
+
def create_model_factories
|
54
|
+
puts "\n"
|
55
|
+
generator = "factory"
|
56
|
+
generator_options = options.to_hash
|
57
|
+
working_generated_code_line_length = ::ShouldaMatchmakers.configuration.preferred_generated_code_line_length - 6
|
58
|
+
SpinToWin.with_spinner('ShouldaMatchmakers:Factories') do |spinner|
|
59
|
+
spinner.banner('initializing...')
|
60
|
+
load_application
|
61
|
+
@app_active_record_descendants_names = get_app_active_record_descendants_names
|
62
|
+
end
|
63
|
+
puts "\n"
|
64
|
+
generate_active_record_model_factories(generator, generator_options, @app_active_record_descendants_names, working_generated_code_line_length)
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def generate_active_record_model_factories(generator, generator_options, app_active_record_descendants_names, code_line_length)
|
71
|
+
if app_active_record_descendants_names.present?
|
72
|
+
selected_app_active_record_descendants_names = filter_app_active_record_descendants_names(generator, generator_options, app_active_record_descendants_names)
|
73
|
+
selected_app_active_record_descendants_names.each do |app_class_name|
|
74
|
+
save_generate(app_class_name, generator) do
|
75
|
+
@active_record_model_factory_sm_model = ::ShouldaMatchmakers::Model::ActiveRecord::FactorySmModel.new(app_class_name, code_line_length)
|
76
|
+
template_filename = File.expand_path('../../templates/factory/active_record/factory_template.haml', File.dirname(__FILE__))
|
77
|
+
template = File.read(template_filename)
|
78
|
+
create_file "#{ ::ShouldaMatchmakers.configuration.active_record_model_factories_path }/#{ app_class_name.underscore }_factory.rb",
|
79
|
+
Haml::Engine.new(template, filename: template_filename, format: :html5).to_html(binding)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module ShouldaMatchmakers
|
2
|
+
class InstallGenerator < Rails::Generators::Base
|
3
|
+
source_root(File.expand_path(File.dirname(__FILE__)))
|
4
|
+
|
5
|
+
def copy_initializer
|
6
|
+
copy_file '../../templates/shoulda_matchmakers.rb', 'config/initializers/shoulda_matchmakers.rb'
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'haml'
|
2
|
+
require_relative 'model_matcher_generator_helper'
|
3
|
+
require 'model/active_record/active_record_model_sm_model'
|
4
|
+
require 'spin_to_win'
|
5
|
+
|
6
|
+
module ShouldaMatchmakers
|
7
|
+
class ModelMatcherGenerator < ::Rails::Generators::Base
|
8
|
+
|
9
|
+
include Generator::ActiveRecord::ModelMatcherGeneratorHelper
|
10
|
+
|
11
|
+
source_root(File.expand_path(File.dirname(__FILE__)))
|
12
|
+
|
13
|
+
class_option :include, type: :array,
|
14
|
+
require: false,
|
15
|
+
aliases: '-i',
|
16
|
+
default: [],
|
17
|
+
desc: "Sets list of application ActiveRecord models to INCLUDE in generated tests.\n" +
|
18
|
+
" By default, tests are generated for all ActiveRecord::Base descendant classes.\n" +
|
19
|
+
" When used, '_included' and '_excluded' settings in '~/config/initializers/shoulda_matchmakers.rb'\n" +
|
20
|
+
" configuration file are ignored. Example (space delimited, include namespaces):\n\n" +
|
21
|
+
" -i Driver License Vehicle::Car Vehicle::Bus\n\n\n"
|
22
|
+
|
23
|
+
class_option :exclude, type: :array,
|
24
|
+
require: false,
|
25
|
+
aliases: '-e',
|
26
|
+
default: [],
|
27
|
+
desc: "Sets list of application ActiveRecord models to EXCLUDE from generated tests.\n" +
|
28
|
+
" By default, no ActiveRecord::Base descendant classes are excluded from generated tests.\n" +
|
29
|
+
" When used, '_included' and '_excluded' settings in '~/config/initializers/shoulda_matchmakers.rb'\n" +
|
30
|
+
" configuration file are ignored. Example (space delimited, include namespaces):\n\n" +
|
31
|
+
" -e Driver Vehicle::Car\n\n\n"
|
32
|
+
|
33
|
+
class_option :include_and_config, type: :array,
|
34
|
+
require: false,
|
35
|
+
aliases: '-I',
|
36
|
+
default: [],
|
37
|
+
desc: "Same as '-i/-include', except that '_included' and '_excluded' settings in\n" +
|
38
|
+
" '~/config/initializers/shoulda_matchmakers.rb' are not ignored. Configuration file\n" +
|
39
|
+
" settings are applied first then the class names listed with this option are applied.\n" +
|
40
|
+
" Example (space delimited, include namespaces):\n\n" +
|
41
|
+
" -I Driver License Vehicle::Car Vehicle::Bus\n\n\n"
|
42
|
+
|
43
|
+
class_option :exclude_and_config, type: :array,
|
44
|
+
require: false,
|
45
|
+
aliases: '-E',
|
46
|
+
default: [],
|
47
|
+
desc: "Same as '-e/-exclude', except that '_included' and '_excluded' settings in\n" +
|
48
|
+
" '~/config/initializers/shoulda_matchmakers.rb' are not ignored. Configuration file\n" +
|
49
|
+
" settings are applied first then the class names listed with this option are applied.\n" +
|
50
|
+
" Example (space delimited, include namespaces):\n\n" +
|
51
|
+
" -E Driver Vehicle::Car\n\n\n"
|
52
|
+
|
53
|
+
def create_model_matchmakers
|
54
|
+
puts "\n"
|
55
|
+
generator = "model"
|
56
|
+
generator_options = options.to_hash
|
57
|
+
working_generated_code_line_length = ::ShouldaMatchmakers.configuration.preferred_generated_code_line_length - 6
|
58
|
+
SpinToWin.with_spinner('ShouldaMatchmakers:ModelMatchers') do |spinner|
|
59
|
+
spinner.banner('initializing...')
|
60
|
+
load_application
|
61
|
+
@app_active_record_descendants_names = get_app_active_record_descendants_names
|
62
|
+
end
|
63
|
+
puts "\n"
|
64
|
+
generate_active_record_model_matchmakers(generator, generator_options, @app_active_record_descendants_names, working_generated_code_line_length)
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def generate_active_record_model_matchmakers(generator, generator_options, app_active_record_descendants_names, code_line_length)
|
71
|
+
if app_active_record_descendants_names.present?
|
72
|
+
selected_app_active_record_descendants_names = filter_app_active_record_descendants_names(generator, generator_options, app_active_record_descendants_names)
|
73
|
+
selected_app_active_record_descendants_names.each do |app_class_name|
|
74
|
+
save_generate(app_class_name, generator) do
|
75
|
+
@active_record_model_sm_model = ::ShouldaMatchmakers::Model::ActiveRecord::ActiveRecordModelSmModel.new(app_class_name, app_active_record_descendants_names, code_line_length)
|
76
|
+
template_filename = File.expand_path('../../templates/model/active_record/model_spec_template.haml', File.dirname(__FILE__))
|
77
|
+
template = File.read(template_filename)
|
78
|
+
create_file "#{ ::ShouldaMatchmakers.configuration.active_record_model_tests_path }/#{ app_class_name.underscore }_spec.rb",
|
79
|
+
Haml::Engine.new(template, filename: template_filename, format: :html5).to_html(binding)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module ShouldaMatchmakers
|
2
|
+
module Generator
|
3
|
+
module ActiveRecord
|
4
|
+
module ModelMatcherGeneratorHelper
|
5
|
+
|
6
|
+
def load_application
|
7
|
+
Rails.application.try(:eager_load!)
|
8
|
+
end
|
9
|
+
|
10
|
+
def get_app_active_record_descendants_names
|
11
|
+
if defined?(::ActiveRecord::Base)
|
12
|
+
::ActiveRecord::Base.descendants.map(&:name)
|
13
|
+
else
|
14
|
+
[]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def save_generate(class_name, generator)
|
19
|
+
begin
|
20
|
+
yield
|
21
|
+
rescue => e
|
22
|
+
if generator == "model"
|
23
|
+
puts "Cannot create model spec for #{ class_name }. Reason #{ e.message }"
|
24
|
+
else
|
25
|
+
puts "Cannot create factory for #{ class_name }. Reason #{ e.message }"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def filter_app_active_record_descendants_names(generator, generator_options, app_active_record_class_names)
|
31
|
+
|
32
|
+
generator_include_option_active_record_class_names = generator_options.fetch('include')
|
33
|
+
generator_exclude_option_active_record_class_names = generator_options.fetch('exclude')
|
34
|
+
generator_include_and_config_options_active_record_class_names = generator_options.fetch('include_and_config')
|
35
|
+
generator_exclude_and_config_options_active_record_class_names = generator_options.fetch('exclude_and_config')
|
36
|
+
|
37
|
+
if generator_include_option_active_record_class_names.present?
|
38
|
+
filter_active_record_class_names_with_include_option(app_active_record_class_names, generator_include_option_active_record_class_names)
|
39
|
+
|
40
|
+
elsif generator_exclude_option_active_record_class_names.present?
|
41
|
+
filter_active_record_class_names_with_exclude_option(app_active_record_class_names, generator_exclude_option_active_record_class_names)
|
42
|
+
|
43
|
+
elsif generator_include_and_config_options_active_record_class_names.present?
|
44
|
+
filter_active_record_class_names_with_generator_include_and_config_options(app_active_record_class_names, generator_include_and_config_options_active_record_class_names, generator)
|
45
|
+
|
46
|
+
elsif generator_exclude_and_config_options_active_record_class_names.present?
|
47
|
+
filter_active_record_class_names_with_generator_exclude_and_config_options(app_active_record_class_names, generator_exclude_and_config_options_active_record_class_names, generator)
|
48
|
+
|
49
|
+
else
|
50
|
+
selected_app_active_record_class_names = filter_active_record_class_names_with_config_options(app_active_record_class_names, generator)
|
51
|
+
if selected_app_active_record_class_names.present?
|
52
|
+
selected_app_active_record_class_names
|
53
|
+
else
|
54
|
+
app_active_record_class_names.uniq.sort
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
def filter_active_record_class_names_with_include_option(app_active_record_class_names, include_option_active_record_class_names)
|
61
|
+
app_active_record_class_names.map.select { |app_class_name| include_option_active_record_class_names.include? app_class_name }.uniq.sort
|
62
|
+
end
|
63
|
+
|
64
|
+
def filter_active_record_class_names_with_exclude_option(app_active_record_class_names, exclude_option_active_record_class_names)
|
65
|
+
app_active_record_class_names.map.reject { |app_class_name| exclude_option_active_record_class_names.include? app_class_name }.uniq.sort
|
66
|
+
end
|
67
|
+
|
68
|
+
def filter_active_record_class_names_with_generator_include_and_config_options(app_active_record_class_names, generator_include_and_config_options_active_record_class_names, generator)
|
69
|
+
selected_app_active_record_class_names = filter_active_record_class_names_with_config_options(app_active_record_class_names, generator)
|
70
|
+
if selected_app_active_record_class_names.present?
|
71
|
+
selected_app_active_record_class_names +
|
72
|
+
filter_active_record_class_names_with_include_option(app_active_record_class_names, generator_include_and_config_options_active_record_class_names).uniq.sort
|
73
|
+
else
|
74
|
+
filter_active_record_class_names_with_include_option(app_active_record_class_names, generator_include_and_config_options_active_record_class_names).uniq.sort
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def filter_active_record_class_names_with_generator_exclude_and_config_options(app_active_record_class_names, generator_exclude_and_config_options_active_record_class_names, generator)
|
79
|
+
selected_active_record_model_names = filter_active_record_class_names_with_config_options(app_active_record_class_names, generator)
|
80
|
+
if selected_active_record_model_names.present?
|
81
|
+
filter_active_record_class_names_with_exclude_option(selected_active_record_model_names, generator_exclude_and_config_options_active_record_class_names).uniq.sort
|
82
|
+
else
|
83
|
+
filter_active_record_class_names_with_exclude_option(app_active_record_class_names, generator_exclude_and_config_options_active_record_class_names).uniq.sort
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def filter_active_record_class_names_with_config_options(app_active_record_class_names, generator)
|
88
|
+
if generator == "model"
|
89
|
+
config_included_option_active_record_class_names = ::ShouldaMatchmakers.configuration.active_record_class_names_included
|
90
|
+
config_excluded_option_active_record_class_names = ::ShouldaMatchmakers.configuration.active_record_class_names_excluded
|
91
|
+
else
|
92
|
+
config_included_option_active_record_class_names = ::ShouldaMatchmakers.configuration.active_record_model_class_names_for_factories_included
|
93
|
+
config_excluded_option_active_record_class_names = ::ShouldaMatchmakers.configuration.active_record_model_class_names_for_factories_excluded
|
94
|
+
end
|
95
|
+
if config_included_option_active_record_class_names.present?
|
96
|
+
filter_active_record_class_names_with_include_option(app_active_record_class_names, config_included_option_active_record_class_names).uniq.sort
|
97
|
+
elsif config_excluded_option_active_record_class_names.present?
|
98
|
+
filter_active_record_class_names_with_exclude_option(app_active_record_class_names, config_excluded_option_active_record_class_names).uniq.sort
|
99
|
+
else
|
100
|
+
[]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require_relative 'matchmakers/accept_nested_attributes_for'
|
2
|
+
require_relative 'matchmakers/allow_value'
|
3
|
+
require_relative 'matchmakers/associations'
|
4
|
+
require_relative 'matchmakers/define_enum_for'
|
5
|
+
require_relative 'matchmakers/delegate_method'
|
6
|
+
require_relative 'matchmakers/have_db_column'
|
7
|
+
require_relative 'matchmakers/have_db_index'
|
8
|
+
require_relative 'matchmakers/have_readonly_attribute'
|
9
|
+
require_relative 'matchmakers/have_secure_password'
|
10
|
+
require_relative 'matchmakers/serialize'
|
11
|
+
require_relative 'matchmakers/validations'
|
12
|
+
require_relative 'active_record_model_sm_model_helper'
|
13
|
+
|
14
|
+
|
15
|
+
module ShouldaMatchmakers
|
16
|
+
module Model
|
17
|
+
module ActiveRecord
|
18
|
+
class ActiveRecordModelSmModel
|
19
|
+
|
20
|
+
### Includes ###
|
21
|
+
include Matchmaker::AllowValue
|
22
|
+
include Matchmaker::Associations
|
23
|
+
include Matchmaker::AcceptNestedAttributesFor
|
24
|
+
include Matchmaker::DefineEnumFor
|
25
|
+
include Matchmaker::DelegateMethod
|
26
|
+
include Matchmaker::HaveDbColumn
|
27
|
+
include Matchmaker::HaveDbIndex
|
28
|
+
include Matchmaker::HaveReadonlyAttribute
|
29
|
+
include Matchmaker::HaveSecurePassword
|
30
|
+
include Matchmaker::Serialize
|
31
|
+
include Matchmaker::Validations
|
32
|
+
include ActiveRecordModelSmModelHelper
|
33
|
+
|
34
|
+
|
35
|
+
### Attribute Accessors ###
|
36
|
+
attr_accessor :app_class_name,
|
37
|
+
:working_generated_code_line_length
|
38
|
+
|
39
|
+
|
40
|
+
### Methods ###
|
41
|
+
def initialize(app_class_name, app_active_record_descendants_names, code_line_length)
|
42
|
+
@app_class_name = app_class_name
|
43
|
+
@app_active_record_descendants_names = app_active_record_descendants_names
|
44
|
+
@working_generated_code_line_length = code_line_length
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,206 @@
|
|
1
|
+
require 'model/active_record/options_definition'
|
2
|
+
|
3
|
+
module ShouldaMatchmakers
|
4
|
+
module Model
|
5
|
+
module ActiveRecord
|
6
|
+
module ActiveRecordModelSmModelHelper
|
7
|
+
|
8
|
+
|
9
|
+
def compose_extended_model_file_path(app_class_name)
|
10
|
+
Rails.root.join("app", "models").to_s + "/" + app_class_name.underscore.concat(".rb")
|
11
|
+
end
|
12
|
+
|
13
|
+
def extract_validators(app_class_name, validator_type)
|
14
|
+
extracted_validators = app_class_name.constantize.validators.select do |validator|
|
15
|
+
validator.class.to_s == validator_type.to_s
|
16
|
+
end
|
17
|
+
extracted_validators.flatten
|
18
|
+
end
|
19
|
+
|
20
|
+
def conditional_options_exist(validator_options)
|
21
|
+
if validator_options.key?(:if) || validator_options.key?(:unless)
|
22
|
+
true
|
23
|
+
else
|
24
|
+
false
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def parse_validator_options(validator_options)
|
29
|
+
non_conditional_options = validator_options
|
30
|
+
if validator_options.key?(:if)
|
31
|
+
if_option_values = non_conditional_options.delete(:if)
|
32
|
+
if_option_values = [if_option_values] if !if_option_values.is_a?(Array)
|
33
|
+
else
|
34
|
+
if_option_values = []
|
35
|
+
end
|
36
|
+
if validator_options.key?(:unless)
|
37
|
+
unless_option_values = non_conditional_options.delete(:unless)
|
38
|
+
unless_option_values = [unless_option_values] if !unless_option_values.is_a?(Array)
|
39
|
+
else
|
40
|
+
unless_option_values = []
|
41
|
+
end
|
42
|
+
{ non_conditional_options: non_conditional_options, if_option_values: if_option_values, unless_option_values: unless_option_values }
|
43
|
+
end
|
44
|
+
|
45
|
+
def order_options(options)
|
46
|
+
options_unordered = options.dup
|
47
|
+
options_ordered = {}
|
48
|
+
options_ordered = options_ordered.merge({ :in=>options_unordered.delete(:in) }) if options_unordered.include?(:in)
|
49
|
+
options_ordered = options_ordered.merge({ :minimum=>options_unordered.delete(:minimum) }) if options_unordered.include?(:minimum)
|
50
|
+
options_ordered = options_ordered.merge({ :maximum=>options_unordered.delete(:maximum) }) if options_unordered.include?(:maximum)
|
51
|
+
options_ordered.merge(options_unordered)
|
52
|
+
end
|
53
|
+
|
54
|
+
def all_option_values_are_symbols(option_values)
|
55
|
+
option_values_are_symbols = true
|
56
|
+
if option_values.present?
|
57
|
+
option_values.each do |option_value|
|
58
|
+
if !option_value.is_a?(Symbol)
|
59
|
+
option_values_are_symbols = false
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
option_values_are_symbols
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_possible_true_false_permutations(validator_options)
|
67
|
+
number_of_conditional_option_values = validator_options[:if_option_values].size +
|
68
|
+
validator_options[:unless_option_values].size
|
69
|
+
[true, false].repeated_permutation(number_of_conditional_option_values).to_a
|
70
|
+
end
|
71
|
+
|
72
|
+
def get_validating_true_false_permutation(validator_options)
|
73
|
+
validating_permutation = []
|
74
|
+
validator_options[:if_option_values].size.times do |n|
|
75
|
+
validating_permutation << true
|
76
|
+
end
|
77
|
+
validator_options[:unless_option_values].size.times do |n|
|
78
|
+
validating_permutation << false
|
79
|
+
end
|
80
|
+
validating_permutation
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_options_string(options)
|
84
|
+
options_hash = ::ShouldaMatchmakers::Model::ActiveRecord::OptionsDefinition.new.options_hash
|
85
|
+
options_string = ""
|
86
|
+
options.map do |option_key, option_value|
|
87
|
+
if options_hash.key?(option_key)
|
88
|
+
option_string = options_hash[option_key].to_s
|
89
|
+
option_value_refined = apply_option_value_qualifiers(option_value, option_string)
|
90
|
+
option_string = option_string.gsub(/\s*\{\s*/,"").gsub(/\s*\}\s*/,"").gsub(/option_value(?:\.[a-zA-Z0-9_]+)*/, option_value_refined)
|
91
|
+
options_string.concat("." + option_string)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
options_string
|
95
|
+
end
|
96
|
+
|
97
|
+
def apply_option_value_qualifiers(option_value, association_option_string)
|
98
|
+
option_value_refined = option_value
|
99
|
+
option_value_qualifiers = association_option_string.scan(/(?: option_value|\.[a-zA-Z0-9_]+)(\.[a-zA-Z0-9_]+)/)
|
100
|
+
option_value_qualifiers.each do |option_value_qualifier|
|
101
|
+
case option_value_qualifier
|
102
|
+
when ".first"
|
103
|
+
option_value_refined = option_value_refined.first
|
104
|
+
when ".last"
|
105
|
+
option_value_refined = option_value_refined.last
|
106
|
+
when ".to_s"
|
107
|
+
option_value_refined = option_value_refined.to_s
|
108
|
+
end
|
109
|
+
end
|
110
|
+
option_value_refined.to_s
|
111
|
+
end
|
112
|
+
|
113
|
+
def compose_conditional_validating_context_string(validator_options)
|
114
|
+
validating_context_string = " context \""
|
115
|
+
conditional_option_values = validator_options[:if_option_values] + validator_options[:unless_option_values]
|
116
|
+
conditional_option_values.each_with_index do |option_value, cov_index|
|
117
|
+
if cov_index < validator_options[:if_option_values].size
|
118
|
+
validating_context_string.concat("if #{ option_value.to_s.chomp('?')} and ")
|
119
|
+
else
|
120
|
+
validating_context_string.concat("unless #{ option_value.to_s.chomp('?')} and ")
|
121
|
+
end
|
122
|
+
end
|
123
|
+
validating_context_string.chomp!(" and ").concat("\" do\n")
|
124
|
+
end
|
125
|
+
|
126
|
+
def compose_conditional_non_validating_context_string(validator_options, non_validating_permutation)
|
127
|
+
non_validating_context_string = " context \""
|
128
|
+
conditional_option_values = validator_options[:if_option_values] + validator_options[:unless_option_values]
|
129
|
+
conditional_option_values.each_with_index do |conditional_option_value, cov_index|
|
130
|
+
if cov_index < validator_options[:if_option_values].size
|
131
|
+
non_validating_context_string.concat(get_if_context_condition(conditional_option_value, non_validating_permutation[cov_index]))
|
132
|
+
else
|
133
|
+
non_validating_context_string.concat(get_unless_context_condition(conditional_option_value, non_validating_permutation[cov_index]))
|
134
|
+
end
|
135
|
+
end
|
136
|
+
non_validating_context_string.chomp!(" and ").concat("\" do\n")
|
137
|
+
end
|
138
|
+
|
139
|
+
def get_if_context_condition(option_value, permutation_boolean_value_for_option)
|
140
|
+
if permutation_boolean_value_for_option
|
141
|
+
if_context_condition = "if #{ option_value.to_s.chomp('?')} and "
|
142
|
+
else
|
143
|
+
if_context_condition = "if not #{ option_value.to_s.chomp('?')} and "
|
144
|
+
end
|
145
|
+
if_context_condition
|
146
|
+
end
|
147
|
+
|
148
|
+
def get_unless_context_condition(option_value, permutation_boolean_value_for_option)
|
149
|
+
if permutation_boolean_value_for_option
|
150
|
+
unless_context_condition = "if (unless not) #{ option_value.to_s.chomp('?')} and "
|
151
|
+
else
|
152
|
+
unless_context_condition = "if not (unless) #{ option_value.to_s.chomp('?')} and "
|
153
|
+
end
|
154
|
+
unless_context_condition
|
155
|
+
end
|
156
|
+
|
157
|
+
def compose_conditional_before_strings(validator_options, conditional_options_permutation)
|
158
|
+
conditional_before_strings = ""
|
159
|
+
conditional_option_values = validator_options[:if_option_values] + validator_options[:unless_option_values]
|
160
|
+
conditional_option_values.each_with_index do |conditional_option_value, cov_index|
|
161
|
+
conditional_before_strings.concat(" before { allow(subject).to receive(:#{ conditional_option_value }).and_return(#{ conditional_options_permutation[cov_index] }) }\n")
|
162
|
+
end
|
163
|
+
conditional_before_strings
|
164
|
+
end
|
165
|
+
|
166
|
+
def append_element(element, element_set)
|
167
|
+
if element.present?
|
168
|
+
element_set << element
|
169
|
+
end
|
170
|
+
element_set
|
171
|
+
end
|
172
|
+
|
173
|
+
def adjust_conditional_test_indentation(conditional_test)
|
174
|
+
if conditional_test.include?("\n")
|
175
|
+
conditional_test.sub(" it do\n","\n it do\n").
|
176
|
+
sub("it do\n ","it do\n ").
|
177
|
+
gsub(").\n ",").\n ").
|
178
|
+
sub("\n end","\n end")
|
179
|
+
else
|
180
|
+
conditional_test.sub(" it {", "\n it {")
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def format_tests(tests)
|
185
|
+
formatted_tests = properly_line_space_tests(tests)
|
186
|
+
formatted_tests.flatten.compact.uniq.join("\n")
|
187
|
+
end
|
188
|
+
|
189
|
+
def properly_line_space_tests(tests)
|
190
|
+
tests_properly_line_spaced = []
|
191
|
+
previous_test = ""
|
192
|
+
tests.each do |test|
|
193
|
+
if (test.include?("\n") && previous_test.present?) ||
|
194
|
+
(!test.include?("\n") && previous_test.include?("\n"))
|
195
|
+
test = "\n" + test
|
196
|
+
end
|
197
|
+
tests_properly_line_spaced << test
|
198
|
+
previous_test = test
|
199
|
+
end
|
200
|
+
tests_properly_line_spaced
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|