shoulda-matchers 3.0.1 → 3.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 +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +3 -3
- data/CONTRIBUTING.md +60 -28
- data/Gemfile +1 -0
- data/Gemfile.lock +15 -12
- data/NEWS.md +111 -0
- data/README.md +94 -6
- data/Rakefile +10 -8
- data/custom_plan.rb +88 -0
- data/gemfiles/4.0.0.gemfile +1 -0
- data/gemfiles/4.0.0.gemfile.lock +21 -18
- data/gemfiles/4.0.1.gemfile +1 -0
- data/gemfiles/4.0.1.gemfile.lock +21 -18
- data/gemfiles/4.1.gemfile +1 -0
- data/gemfiles/4.1.gemfile.lock +21 -18
- data/gemfiles/4.2.gemfile +1 -0
- data/gemfiles/4.2.gemfile.lock +24 -21
- data/lib/shoulda/matchers/action_controller/permit_matcher.rb +6 -11
- data/lib/shoulda/matchers/active_model.rb +10 -1
- data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +258 -180
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_changed_value_error.rb +45 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_does_not_exist_error.rb +23 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb +236 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter_and_validator.rb +62 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters.rb +40 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters_and_validators.rb +48 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher/successful_check.rb +14 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher/successful_setting.rb +14 -0
- data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +34 -14
- data/lib/shoulda/matchers/active_model/helpers.rb +9 -17
- data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +13 -6
- data/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb +13 -2
- data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +19 -35
- data/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb +13 -2
- data/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb +12 -2
- data/lib/shoulda/matchers/active_model/qualifiers.rb +12 -0
- data/lib/shoulda/matchers/active_model/qualifiers/ignore_interference_by_writer.rb +101 -0
- data/lib/shoulda/matchers/active_model/qualifiers/ignoring_interference_by_writer.rb +21 -0
- data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +30 -32
- data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +5 -8
- data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +22 -22
- data/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +27 -16
- data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +58 -15
- data/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +22 -12
- data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +165 -87
- data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +7 -9
- data/lib/shoulda/matchers/active_model/validation_matcher.rb +111 -49
- data/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb +60 -0
- data/lib/shoulda/matchers/active_model/validator.rb +71 -52
- data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +19 -5
- data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +450 -124
- data/lib/shoulda/matchers/util.rb +43 -0
- data/lib/shoulda/matchers/util/word_wrap.rb +59 -31
- data/lib/shoulda/matchers/version.rb +1 -1
- data/script/update_gem_in_all_appraisals +1 -1
- data/script/update_gems_in_all_appraisals +1 -1
- data/spec/acceptance/multiple_libraries_integration_spec.rb +5 -2
- data/spec/acceptance/rails_integration_spec.rb +6 -2
- data/spec/spec_helper.rb +1 -3
- data/spec/support/acceptance/helpers/step_helpers.rb +4 -1
- data/spec/support/tests/current_bundle.rb +21 -7
- data/spec/support/unit/active_record/create_table.rb +54 -0
- data/spec/support/unit/attribute.rb +47 -0
- data/spec/support/unit/capture.rb +6 -0
- data/spec/support/unit/change_value.rb +111 -0
- data/spec/support/unit/create_model_arguments/basic.rb +135 -0
- data/spec/support/unit/create_model_arguments/has_many.rb +15 -0
- data/spec/support/unit/create_model_arguments/uniqueness_matcher.rb +74 -0
- data/spec/support/unit/helpers/active_record_versions.rb +1 -1
- data/spec/support/unit/helpers/class_builder.rb +61 -47
- data/spec/support/unit/helpers/database_helpers.rb +5 -3
- data/spec/support/unit/helpers/model_builder.rb +77 -97
- data/spec/support/unit/helpers/validation_matcher_scenario_helpers.rb +44 -0
- data/spec/support/unit/load_environment.rb +12 -0
- data/spec/support/unit/matchers/fail_with_message_including_matcher.rb +2 -2
- data/spec/support/unit/matchers/fail_with_message_matcher.rb +12 -1
- data/spec/support/unit/model_creation_strategies/active_model.rb +111 -0
- data/spec/support/unit/model_creation_strategies/active_record.rb +77 -0
- data/spec/support/unit/model_creators.rb +19 -0
- data/spec/support/unit/model_creators/active_model.rb +39 -0
- data/spec/support/unit/model_creators/active_record.rb +43 -0
- data/spec/support/unit/model_creators/active_record/has_and_belongs_to_many.rb +95 -0
- data/spec/support/unit/model_creators/active_record/has_many.rb +67 -0
- data/spec/support/unit/model_creators/active_record/uniqueness_matcher.rb +42 -0
- data/spec/support/unit/model_creators/basic.rb +97 -0
- data/spec/support/unit/rails_application.rb +1 -1
- data/spec/support/unit/record_validating_confirmation_builder.rb +3 -7
- data/spec/support/unit/shared_examples/ignoring_interference_by_writer.rb +79 -0
- data/spec/support/unit/validation_matcher_scenario.rb +62 -0
- data/spec/unit/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb +4 -0
- data/spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb +575 -140
- data/spec/unit/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb +115 -15
- data/spec/unit/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +42 -4
- data/spec/unit/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb +92 -6
- data/spec/unit/shoulda/matchers/active_model/validate_exclusion_of_matcher_spec.rb +122 -10
- data/spec/unit/shoulda/matchers/active_model/validate_inclusion_of_matcher_spec.rb +306 -58
- data/spec/unit/shoulda/matchers/active_model/validate_length_of_matcher_spec.rb +122 -3
- data/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +805 -131
- data/spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +196 -29
- data/spec/unit/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb +82 -40
- data/spec/unit/shoulda/matchers/active_record/validate_uniqueness_of_matcher_spec.rb +600 -101
- data/spec/unit/shoulda/matchers/util/word_wrap_spec.rb +88 -33
- data/spec/unit_spec_helper.rb +10 -22
- data/zeus.json +11 -0
- metadata +64 -23
- data/lib/shoulda/matchers/active_model/strict_validator.rb +0 -51
- data/spec/support/unit/shared_examples/numerical_type_submatcher.rb +0 -15
- data/spec/unit/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb +0 -288
- data/spec/unit/shoulda/matchers/active_model/numericality_matchers/even_number_matcher_spec.rb +0 -100
- data/spec/unit/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher_spec.rb +0 -100
- data/spec/unit/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher_spec.rb +0 -100
@@ -9,10 +9,12 @@ module UnitTests
|
|
9
9
|
Tests::Database.instance.adapter_name
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
12
|
+
def postgresql?
|
13
13
|
database_adapter == :postgresql
|
14
14
|
end
|
15
|
-
|
16
|
-
|
15
|
+
|
16
|
+
alias_method :database_supports_array_columns?, :postgresql?
|
17
|
+
alias_method :database_supports_uuid_columns?, :postgresql?
|
18
|
+
alias_method :database_supports_money_columns?, :postgresql?
|
17
19
|
end
|
18
20
|
end
|
@@ -2,133 +2,113 @@ require_relative 'class_builder'
|
|
2
2
|
|
3
3
|
module UnitTests
|
4
4
|
module ModelBuilder
|
5
|
-
|
6
|
-
|
7
|
-
def self.configure_example_group(example_group)
|
8
|
-
example_group.include(self)
|
9
|
-
|
10
|
-
example_group.after do
|
11
|
-
clear_column_caches
|
12
|
-
drop_created_tables
|
13
|
-
end
|
5
|
+
def create_table(*args, &block)
|
6
|
+
ModelBuilder.create_table(*args, &block)
|
14
7
|
end
|
15
8
|
|
16
|
-
def
|
17
|
-
|
18
|
-
|
19
|
-
begin
|
20
|
-
connection.execute("DROP TABLE IF EXISTS #{table_name}")
|
21
|
-
connection.create_table(table_name, options, &block)
|
22
|
-
created_tables << table_name
|
23
|
-
connection
|
24
|
-
rescue Exception => e
|
25
|
-
connection.execute("DROP TABLE IF EXISTS #{table_name}")
|
26
|
-
raise e
|
27
|
-
end
|
9
|
+
def define_model(*args, &block)
|
10
|
+
ModelBuilder.define_model(*args, &block)
|
28
11
|
end
|
29
12
|
|
30
|
-
def define_model_class(
|
31
|
-
|
13
|
+
def define_model_class(*args, &block)
|
14
|
+
ModelBuilder.define_model_class(*args, &block)
|
32
15
|
end
|
33
16
|
|
34
|
-
def define_active_model_class(
|
35
|
-
|
36
|
-
|
37
|
-
define_class(class_name) do
|
38
|
-
include ActiveModel::Validations
|
17
|
+
def define_active_model_class(*args, &block)
|
18
|
+
ModelBuilder.define_active_model_class(*args, &block)
|
19
|
+
end
|
39
20
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
end
|
44
|
-
end
|
21
|
+
class << self
|
22
|
+
def configure_example_group(example_group)
|
23
|
+
example_group.include(self)
|
45
24
|
|
46
|
-
|
47
|
-
|
25
|
+
example_group.after do
|
26
|
+
ModelBuilder.reset
|
48
27
|
end
|
28
|
+
end
|
49
29
|
|
50
|
-
|
51
|
-
|
52
|
-
|
30
|
+
def reset
|
31
|
+
clear_column_caches
|
32
|
+
drop_created_tables
|
33
|
+
created_tables.clear
|
34
|
+
defined_models.clear
|
53
35
|
end
|
54
|
-
end
|
55
36
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
column_options = {}
|
68
|
-
end
|
69
|
-
|
70
|
-
begin
|
71
|
-
table.__send__(column_type, column_name, column_options)
|
72
|
-
rescue NoMethodError
|
73
|
-
raise NoMethodError, "#{Tests::Database.instance.adapter_class} does not support :#{column_type} columns"
|
74
|
-
end
|
37
|
+
def create_table(table_name, options = {}, &block)
|
38
|
+
connection = ::ActiveRecord::Base.connection
|
39
|
+
|
40
|
+
begin
|
41
|
+
connection.execute("DROP TABLE IF EXISTS #{table_name}")
|
42
|
+
connection.create_table(table_name, options, &block)
|
43
|
+
created_tables << table_name
|
44
|
+
connection
|
45
|
+
rescue Exception => e
|
46
|
+
connection.execute("DROP TABLE IF EXISTS #{table_name}")
|
47
|
+
raise e
|
75
48
|
end
|
76
49
|
end
|
77
50
|
|
78
|
-
|
79
|
-
|
80
|
-
create_table(table_name, id: false, &table_block)
|
81
|
-
else
|
82
|
-
create_table(table_name, &table_block)
|
51
|
+
def define_model_class(class_name, &block)
|
52
|
+
ClassBuilder.define_class(class_name, ::ActiveRecord::Base, &block)
|
83
53
|
end
|
84
54
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
block.call(m)
|
91
|
-
end
|
55
|
+
def define_active_model_class(class_name, options = {}, &block)
|
56
|
+
attribute_names = options.delete(:accessors) { [] }
|
57
|
+
|
58
|
+
columns = attribute_names.reduce({}) do |hash, attribute_name|
|
59
|
+
hash.merge(attribute_name => nil)
|
92
60
|
end
|
93
61
|
|
94
|
-
|
62
|
+
UnitTests::ModelCreationStrategies::ActiveModel.call(
|
63
|
+
'Example',
|
64
|
+
columns,
|
65
|
+
options,
|
66
|
+
&block
|
67
|
+
)
|
95
68
|
end
|
96
69
|
|
97
|
-
|
70
|
+
def define_model(name, columns = {}, options = {}, &block)
|
71
|
+
model = UnitTests::ModelCreationStrategies::ActiveRecord.call(
|
72
|
+
name,
|
73
|
+
columns,
|
74
|
+
options,
|
75
|
+
&block
|
76
|
+
)
|
77
|
+
defined_models << model
|
78
|
+
model
|
79
|
+
end
|
98
80
|
|
99
|
-
|
100
|
-
end
|
81
|
+
private
|
101
82
|
|
102
|
-
|
83
|
+
def clear_column_caches
|
84
|
+
# Rails 4.x
|
85
|
+
if ::ActiveRecord::Base.connection.respond_to?(:schema_cache)
|
86
|
+
::ActiveRecord::Base.connection.schema_cache.clear!
|
87
|
+
# Rails 3.1 - 4.0
|
88
|
+
elsif ::ActiveRecord::Base.connection_pool.respond_to?(:clear_cache!)
|
89
|
+
::ActiveRecord::Base.connection_pool.clear_cache!
|
90
|
+
end
|
103
91
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
ActiveRecord::Base.connection.schema_cache.clear!
|
108
|
-
# Rails 3.1 - 4.0
|
109
|
-
elsif ActiveRecord::Base.connection_pool.respond_to?(:clear_cache!)
|
110
|
-
ActiveRecord::Base.connection_pool.clear_cache!
|
92
|
+
defined_models.each do |model|
|
93
|
+
model.reset_column_information
|
94
|
+
end
|
111
95
|
end
|
112
96
|
|
113
|
-
|
114
|
-
|
115
|
-
end
|
116
|
-
end
|
97
|
+
def drop_created_tables
|
98
|
+
connection = ::ActiveRecord::Base.connection
|
117
99
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
created_tables.each do |table_name|
|
122
|
-
connection.execute("DROP TABLE IF EXISTS #{table_name}")
|
100
|
+
created_tables.each do |table_name|
|
101
|
+
connection.execute("DROP TABLE IF EXISTS #{table_name}")
|
102
|
+
end
|
123
103
|
end
|
124
|
-
end
|
125
104
|
|
126
|
-
|
127
|
-
|
128
|
-
|
105
|
+
def created_tables
|
106
|
+
@_created_tables ||= []
|
107
|
+
end
|
129
108
|
|
130
|
-
|
131
|
-
|
109
|
+
def defined_models
|
110
|
+
@_defined_models ||= []
|
111
|
+
end
|
132
112
|
end
|
133
113
|
end
|
134
114
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module UnitTests
|
2
|
+
module ValidationMatcherScenarioHelpers
|
3
|
+
def self.configure_example_group(example_group)
|
4
|
+
example_group.include(self)
|
5
|
+
end
|
6
|
+
|
7
|
+
def build_scenario_for_validation_matcher(args)
|
8
|
+
UnitTests::ValidationMatcherScenario.new(
|
9
|
+
build_validation_matcher_scenario_args(args)
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
def validation_matcher_scenario_args
|
16
|
+
{}
|
17
|
+
end
|
18
|
+
|
19
|
+
def configure_validation_matcher(matcher)
|
20
|
+
matcher
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def build_validation_matcher_scenario_args(args)
|
26
|
+
args.
|
27
|
+
deep_merge(validation_matcher_scenario_args).
|
28
|
+
deep_merge(
|
29
|
+
matcher_name: matcher_name,
|
30
|
+
matcher_proc: method(matcher_name)
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
def matcher_name
|
35
|
+
validation_matcher_scenario_args.fetch(:matcher_name) do
|
36
|
+
raise KeyNotFoundError.new(<<-MESSAGE)
|
37
|
+
Please implement #validation_matcher_scenario_args in your example
|
38
|
+
group, in such a way that it returns a hash that contains a
|
39
|
+
:matcher_name key.
|
40
|
+
MESSAGE
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require_relative '../tests/current_bundle'
|
2
|
+
require_relative 'rails_application'
|
3
|
+
|
4
|
+
Tests::CurrentBundle.instance.assert_appraisal!
|
5
|
+
|
6
|
+
$test_app = UnitTests::RailsApplication.new
|
7
|
+
$test_app.create
|
8
|
+
$test_app.load
|
9
|
+
|
10
|
+
require 'active_record/base'
|
11
|
+
|
12
|
+
ENV['RAILS_ENV'] = 'test'
|
@@ -24,10 +24,10 @@ module UnitTests
|
|
24
24
|
lines << Shoulda::Matchers::Util.indent(expected, 2)
|
25
25
|
|
26
26
|
if @actual
|
27
|
-
lines << '
|
27
|
+
lines << 'The full message was:'
|
28
28
|
lines << Shoulda::Matchers::Util.indent(@actual, 2)
|
29
29
|
else
|
30
|
-
lines << 'However, the expectation did not fail.'
|
30
|
+
lines << 'However, the expectation did not fail at all.'
|
31
31
|
end
|
32
32
|
|
33
33
|
lines.join("\n")
|
@@ -26,8 +26,13 @@ module UnitTests
|
|
26
26
|
if @actual
|
27
27
|
lines << 'Actually failed with:'
|
28
28
|
lines << Shoulda::Matchers::Util.indent(@actual, 2)
|
29
|
+
lines << "Diff:"
|
30
|
+
lines << Shoulda::Matchers::Util.indent(
|
31
|
+
differ.diff(@actual, expected)[1..-1],
|
32
|
+
2
|
33
|
+
)
|
29
34
|
else
|
30
|
-
lines << 'However, the expectation did not fail.'
|
35
|
+
lines << 'However, the expectation did not fail at all.'
|
31
36
|
end
|
32
37
|
|
33
38
|
lines.join("\n")
|
@@ -46,6 +51,12 @@ module UnitTests
|
|
46
51
|
def failure_message_for_should_not
|
47
52
|
failure_message_when_negated
|
48
53
|
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def differ
|
58
|
+
@_differ ||= RSpec::Support::Differ.new
|
59
|
+
end
|
49
60
|
end
|
50
61
|
end
|
51
62
|
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module UnitTests
|
2
|
+
module ModelCreationStrategies
|
3
|
+
class ActiveModel
|
4
|
+
def self.call(name, columns = {}, options = {}, &block)
|
5
|
+
new(name, columns, options, &block).call
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(name, columns = {}, options = {}, &block)
|
9
|
+
@name = name
|
10
|
+
@columns = columns
|
11
|
+
@options = options
|
12
|
+
@model_customizers = []
|
13
|
+
|
14
|
+
if block
|
15
|
+
customize_model(&block)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def customize_model(&block)
|
20
|
+
model_customizers << block
|
21
|
+
end
|
22
|
+
|
23
|
+
def call
|
24
|
+
ClassBuilder.define_class(name, Model).tap do |model|
|
25
|
+
model.columns = columns.keys
|
26
|
+
|
27
|
+
model_customizers.each do |block|
|
28
|
+
run_block(model, block)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
protected
|
34
|
+
|
35
|
+
attr_reader :name, :columns, :model_customizers, :options
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def run_block(model, block)
|
40
|
+
if block
|
41
|
+
if block.arity == 0
|
42
|
+
model.class_eval(&block)
|
43
|
+
else
|
44
|
+
block.call(model)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Model
|
50
|
+
class << self
|
51
|
+
def columns
|
52
|
+
@_columns ||= []
|
53
|
+
end
|
54
|
+
|
55
|
+
def columns=(columns)
|
56
|
+
existing_columns = self.columns
|
57
|
+
new_columns = columns - existing_columns
|
58
|
+
|
59
|
+
@_columns += new_columns
|
60
|
+
|
61
|
+
include attributes_module
|
62
|
+
|
63
|
+
attributes_module.module_eval do
|
64
|
+
new_columns.each do |column|
|
65
|
+
define_method(column) do
|
66
|
+
attributes[column]
|
67
|
+
end
|
68
|
+
|
69
|
+
define_method("#{column}=") do |value|
|
70
|
+
attributes[column] = value
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def attributes_module
|
79
|
+
@_attributes_module ||= Module.new
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
include ::ActiveModel::Model
|
84
|
+
|
85
|
+
attr_reader :attributes
|
86
|
+
|
87
|
+
def initialize(attributes = {})
|
88
|
+
@attributes = attributes.symbolize_keys
|
89
|
+
end
|
90
|
+
|
91
|
+
def inspect
|
92
|
+
middle = '%s:0x%014x%s' % [
|
93
|
+
self.class,
|
94
|
+
object_id * 2,
|
95
|
+
' ' + inspected_attributes.join(' ')
|
96
|
+
]
|
97
|
+
|
98
|
+
"#<#{middle.strip}>"
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def inspected_attributes
|
104
|
+
self.class.columns.map do |key, value|
|
105
|
+
"#{key}: #{attributes[key].inspect}"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module UnitTests
|
2
|
+
module ModelCreationStrategies
|
3
|
+
class ActiveRecord
|
4
|
+
def self.call(name, columns = {}, options = {}, &block)
|
5
|
+
new(name, columns, options, &block).call
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(name, columns = {}, options = {}, &block)
|
9
|
+
@name = name
|
10
|
+
@columns = columns
|
11
|
+
@options = options
|
12
|
+
@model_customizers = []
|
13
|
+
|
14
|
+
if block
|
15
|
+
customize_model(&block)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def customize_model(&block)
|
20
|
+
model_customizers << block
|
21
|
+
end
|
22
|
+
|
23
|
+
def call
|
24
|
+
create_table_for_model
|
25
|
+
define_class_for_model
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
|
30
|
+
attr_reader :columns, :model_customizers, :name, :options
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def create_table_for_model
|
35
|
+
UnitTests::ActiveRecord::CreateTable.call(table_name, columns)
|
36
|
+
end
|
37
|
+
|
38
|
+
def define_class_for_model
|
39
|
+
model = UnitTests::ModelBuilder.define_model_class(class_name)
|
40
|
+
|
41
|
+
model_customizers.each do |block|
|
42
|
+
run_block(model, block)
|
43
|
+
end
|
44
|
+
|
45
|
+
if whitelist_attributes?
|
46
|
+
model.attr_accessible(*columns.keys)
|
47
|
+
end
|
48
|
+
|
49
|
+
model.table_name = table_name
|
50
|
+
|
51
|
+
model
|
52
|
+
end
|
53
|
+
|
54
|
+
def run_block(model, block)
|
55
|
+
if block
|
56
|
+
if block.arity == 0
|
57
|
+
model.class_eval(&block)
|
58
|
+
else
|
59
|
+
block.call(model)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def class_name
|
65
|
+
name.to_s.pluralize.classify
|
66
|
+
end
|
67
|
+
|
68
|
+
def table_name
|
69
|
+
class_name.tableize.gsub('/', '_')
|
70
|
+
end
|
71
|
+
|
72
|
+
def whitelist_attributes?
|
73
|
+
options.fetch(:whitelist_attributes, true)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|