command_model 2.0.0 → 2.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/.github/workflows/ci.yml +26 -0
- data/.gitignore +1 -1
- data/.ruby-version +1 -0
- data/.tool-versions +1 -0
- data/Gemfile.lock +50 -0
- data/README.md +135 -54
- data/Rakefile +4 -7
- data/bin/rake +27 -0
- data/command_model.gemspec +4 -5
- data/examples/bank/Gemfile +4 -4
- data/examples/bank/app/controllers/accounts_controller.rb +12 -12
- data/examples/bank/app/controllers/transfers_controller.rb +3 -3
- data/examples/bank/app/views/accounts/deposit_form.html.erb +1 -5
- data/examples/bank/app/views/accounts/withdraw_form.html.erb +1 -5
- data/examples/bank/app/views/layouts/application.html.erb +1 -1
- data/examples/bank/app/views/transfers/new.html.erb +2 -6
- data/examples/bank/config/application.rb +1 -1
- data/examples/bank/config/routes.rb +6 -6
- data/examples/bank/test/performance/browsing_test.rb +2 -2
- data/gemfiles/{5.0.gemfile → 6.1.gemfile} +1 -1
- data/gemfiles/6.1.gemfile.lock +52 -0
- data/gemfiles/{5.1.gemfile → 7.0.gemfile} +1 -1
- data/gemfiles/7.0.gemfile.lock +50 -0
- data/gemfiles/7.1.gemfile +5 -0
- data/gemfiles/7.1.gemfile.lock +60 -0
- data/lib/command_model/convert.rb +1 -1
- data/lib/command_model/model.rb +61 -16
- data/lib/command_model/version.rb +1 -1
- data/spec/convert_spec.rb +5 -4
- data/spec/model_spec.rb +129 -6
- metadata +24 -17
- data/.travis.yml +0 -6
@@ -0,0 +1,52 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ..
|
3
|
+
specs:
|
4
|
+
command_model (2.0.1)
|
5
|
+
activemodel (> 6.1)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
activemodel (6.1.7.7)
|
11
|
+
activesupport (= 6.1.7.7)
|
12
|
+
activesupport (6.1.7.7)
|
13
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
14
|
+
i18n (>= 1.6, < 2)
|
15
|
+
minitest (>= 5.1)
|
16
|
+
tzinfo (~> 2.0)
|
17
|
+
zeitwerk (~> 2.3)
|
18
|
+
concurrent-ruby (1.2.3)
|
19
|
+
diff-lcs (1.5.1)
|
20
|
+
i18n (1.14.4)
|
21
|
+
concurrent-ruby (~> 1.0)
|
22
|
+
minitest (5.22.3)
|
23
|
+
rake (13.1.0)
|
24
|
+
rspec (3.13.0)
|
25
|
+
rspec-core (~> 3.13.0)
|
26
|
+
rspec-expectations (~> 3.13.0)
|
27
|
+
rspec-mocks (~> 3.13.0)
|
28
|
+
rspec-core (3.13.0)
|
29
|
+
rspec-support (~> 3.13.0)
|
30
|
+
rspec-expectations (3.13.0)
|
31
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
32
|
+
rspec-support (~> 3.13.0)
|
33
|
+
rspec-mocks (3.13.0)
|
34
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
35
|
+
rspec-support (~> 3.13.0)
|
36
|
+
rspec-support (3.13.1)
|
37
|
+
tzinfo (2.0.6)
|
38
|
+
concurrent-ruby (~> 1.0)
|
39
|
+
zeitwerk (2.6.13)
|
40
|
+
|
41
|
+
PLATFORMS
|
42
|
+
arm64-darwin-23
|
43
|
+
x86_64-linux
|
44
|
+
|
45
|
+
DEPENDENCIES
|
46
|
+
activemodel (~> 6.1.0)
|
47
|
+
command_model!
|
48
|
+
rake (~> 13.1.0)
|
49
|
+
rspec (~> 3.13.0)
|
50
|
+
|
51
|
+
BUNDLED WITH
|
52
|
+
2.4.3
|
@@ -0,0 +1,50 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ..
|
3
|
+
specs:
|
4
|
+
command_model (2.0.1)
|
5
|
+
activemodel (> 6.1)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
activemodel (7.0.4.3)
|
11
|
+
activesupport (= 7.0.4.3)
|
12
|
+
activesupport (7.0.4.3)
|
13
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
14
|
+
i18n (>= 1.6, < 2)
|
15
|
+
minitest (>= 5.1)
|
16
|
+
tzinfo (~> 2.0)
|
17
|
+
concurrent-ruby (1.2.3)
|
18
|
+
diff-lcs (1.5.1)
|
19
|
+
i18n (1.14.4)
|
20
|
+
concurrent-ruby (~> 1.0)
|
21
|
+
minitest (5.22.3)
|
22
|
+
rake (13.1.0)
|
23
|
+
rspec (3.13.0)
|
24
|
+
rspec-core (~> 3.13.0)
|
25
|
+
rspec-expectations (~> 3.13.0)
|
26
|
+
rspec-mocks (~> 3.13.0)
|
27
|
+
rspec-core (3.13.0)
|
28
|
+
rspec-support (~> 3.13.0)
|
29
|
+
rspec-expectations (3.13.0)
|
30
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
31
|
+
rspec-support (~> 3.13.0)
|
32
|
+
rspec-mocks (3.13.0)
|
33
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
34
|
+
rspec-support (~> 3.13.0)
|
35
|
+
rspec-support (3.13.1)
|
36
|
+
tzinfo (2.0.6)
|
37
|
+
concurrent-ruby (~> 1.0)
|
38
|
+
|
39
|
+
PLATFORMS
|
40
|
+
arm64-darwin-23
|
41
|
+
x86_64-linux
|
42
|
+
|
43
|
+
DEPENDENCIES
|
44
|
+
activemodel (~> 7.0.0)
|
45
|
+
command_model!
|
46
|
+
rake (~> 13.1.0)
|
47
|
+
rspec (~> 3.13.0)
|
48
|
+
|
49
|
+
BUNDLED WITH
|
50
|
+
2.4.3
|
@@ -0,0 +1,60 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ..
|
3
|
+
specs:
|
4
|
+
command_model (2.0.1)
|
5
|
+
activemodel (> 6.1)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
activemodel (7.1.3.2)
|
11
|
+
activesupport (= 7.1.3.2)
|
12
|
+
activesupport (7.1.3.2)
|
13
|
+
base64
|
14
|
+
bigdecimal
|
15
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
16
|
+
connection_pool (>= 2.2.5)
|
17
|
+
drb
|
18
|
+
i18n (>= 1.6, < 2)
|
19
|
+
minitest (>= 5.1)
|
20
|
+
mutex_m
|
21
|
+
tzinfo (~> 2.0)
|
22
|
+
base64 (0.2.0)
|
23
|
+
bigdecimal (3.1.7)
|
24
|
+
concurrent-ruby (1.2.3)
|
25
|
+
connection_pool (2.4.1)
|
26
|
+
diff-lcs (1.5.1)
|
27
|
+
drb (2.2.1)
|
28
|
+
i18n (1.14.4)
|
29
|
+
concurrent-ruby (~> 1.0)
|
30
|
+
minitest (5.22.3)
|
31
|
+
mutex_m (0.2.0)
|
32
|
+
rake (13.1.0)
|
33
|
+
rspec (3.13.0)
|
34
|
+
rspec-core (~> 3.13.0)
|
35
|
+
rspec-expectations (~> 3.13.0)
|
36
|
+
rspec-mocks (~> 3.13.0)
|
37
|
+
rspec-core (3.13.0)
|
38
|
+
rspec-support (~> 3.13.0)
|
39
|
+
rspec-expectations (3.13.0)
|
40
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
41
|
+
rspec-support (~> 3.13.0)
|
42
|
+
rspec-mocks (3.13.0)
|
43
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
44
|
+
rspec-support (~> 3.13.0)
|
45
|
+
rspec-support (3.13.1)
|
46
|
+
tzinfo (2.0.6)
|
47
|
+
concurrent-ruby (~> 1.0)
|
48
|
+
|
49
|
+
PLATFORMS
|
50
|
+
arm64-darwin-23
|
51
|
+
x86_64-linux
|
52
|
+
|
53
|
+
DEPENDENCIES
|
54
|
+
activemodel (~> 7.1.0)
|
55
|
+
command_model!
|
56
|
+
rake (~> 13.1.0)
|
57
|
+
rspec (~> 3.13.0)
|
58
|
+
|
59
|
+
BUNDLED WITH
|
60
|
+
2.4.3
|
@@ -61,7 +61,7 @@ module CommandModel
|
|
61
61
|
return nil if value.blank?
|
62
62
|
return value if value.kind_of? Date
|
63
63
|
value = value.to_s
|
64
|
-
if value =~ /\A(\d
|
64
|
+
if value =~ /\A(\d{4,5})-(\d\d)-(\d\d)\z/
|
65
65
|
::Date.civil($1.to_i, $2.to_i, $3.to_i)
|
66
66
|
else
|
67
67
|
::Date.strptime(value, "%m/%d/%Y")
|
data/lib/command_model/model.rb
CHANGED
@@ -1,18 +1,15 @@
|
|
1
1
|
module CommandModel
|
2
|
-
class TypecastError < StandardError
|
3
|
-
attr_reader :original_error
|
4
|
-
|
5
|
-
def initialize(original_error)
|
6
|
-
@original_error = original_error
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
2
|
class Model
|
11
3
|
include ActiveModel::Validations
|
12
4
|
include ActiveModel::Conversion
|
13
5
|
extend ActiveModel::Naming
|
14
6
|
|
15
|
-
|
7
|
+
def self.inherited(subclass)
|
8
|
+
subclass.instance_variable_set :@parameters, parameters.dup.freeze
|
9
|
+
subclass.instance_variable_set :@dependencies, dependencies.dup.freeze
|
10
|
+
end
|
11
|
+
|
12
|
+
Parameter = Data.define(:name, :converters, :validations)
|
16
13
|
|
17
14
|
# Parameter requires one or more attributes as its first parameter(s).
|
18
15
|
# It accepts an options hash as its last parameter.
|
@@ -34,11 +31,12 @@ module CommandModel
|
|
34
31
|
# parameter :height, :weight,
|
35
32
|
# convert: [CommandModel::Convert::StringMutator.new { |s| s.gsub(",", "")}, :integer],
|
36
33
|
# presence: true,
|
37
|
-
# numericality: { :
|
34
|
+
# numericality: { greater_than_or_equal_to: 0 }
|
38
35
|
def self.parameter(*args)
|
39
36
|
options = args.last.kind_of?(Hash) ? args.pop.clone : {}
|
40
37
|
converters = options.delete(:convert)
|
41
38
|
|
39
|
+
@parameters ||= [].freeze
|
42
40
|
args.each do |name|
|
43
41
|
attr_reader name
|
44
42
|
|
@@ -48,13 +46,13 @@ module CommandModel
|
|
48
46
|
attr_writer name
|
49
47
|
end
|
50
48
|
validates name, options.clone if options.present? # clone options because validates mutates the hash :(
|
51
|
-
parameters
|
49
|
+
@parameters = (@parameters + [Parameter.new(name, converters, options)]).freeze
|
52
50
|
end
|
53
51
|
end
|
54
52
|
|
55
53
|
# Returns array of all parameters defined for class
|
56
54
|
def self.parameters
|
57
|
-
@parameters ||= []
|
55
|
+
@parameters ||= [].freeze
|
58
56
|
end
|
59
57
|
|
60
58
|
def self.attr_type_converting_writer(name, converters) #:nodoc
|
@@ -90,6 +88,38 @@ module CommandModel
|
|
90
88
|
end
|
91
89
|
end
|
92
90
|
|
91
|
+
Dependency = Data.define(:name, :default, :allow_blank)
|
92
|
+
|
93
|
+
# Dependency requires one or more attributes as its first parameter(s). A dependency is something that is required
|
94
|
+
# for the command to execute that is not user supplied input. For example, a database connection, a logger, or the
|
95
|
+
# current user.
|
96
|
+
#
|
97
|
+
# ==== Keyword Arguments
|
98
|
+
#
|
99
|
+
# * default - An object that will be used as the default value for the dependency or a callable object that will be
|
100
|
+
# called to get the default value.
|
101
|
+
# * allow_blank - If true, the dependency can be nil or blank. If false, the dependency must be present.
|
102
|
+
#
|
103
|
+
# ==== Examples
|
104
|
+
#
|
105
|
+
# dependency :current_user
|
106
|
+
# dependency :stdout, default: -> { $stdout }
|
107
|
+
def self.dependency(*names, default: nil, allow_blank: false)
|
108
|
+
@dependencies ||= [].freeze
|
109
|
+
names.each do |name|
|
110
|
+
name = name.to_sym
|
111
|
+
attr_reader name
|
112
|
+
private attr_writer name
|
113
|
+
default_callable = default.respond_to?(:call) ? default : -> { default }
|
114
|
+
@dependencies = (@dependencies + [Dependency.new(name, default_callable, allow_blank)]).freeze
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Returns array of all dependencies defined for class.
|
119
|
+
def self.dependencies
|
120
|
+
@dependencies ||= [].freeze
|
121
|
+
end
|
122
|
+
|
93
123
|
# Executes a block of code if the command model is valid.
|
94
124
|
#
|
95
125
|
# Accepts either a command model or a hash of attributes with which to
|
@@ -97,18 +127,19 @@ module CommandModel
|
|
97
127
|
#
|
98
128
|
# ==== Examples
|
99
129
|
#
|
100
|
-
# RenameUserCommand.execute(:
|
130
|
+
# RenameUserCommand.execute(login: "john") do |command|
|
101
131
|
# if allowed_to_rename_user?
|
102
132
|
# self.login = command.login
|
103
133
|
# else
|
104
134
|
# command.errors.add :base, "not allowed to rename"
|
105
135
|
# end
|
106
136
|
# end
|
107
|
-
def self.execute(attributes_or_command, &block)
|
137
|
+
def self.execute(attributes_or_command, dependencies={}, &block)
|
108
138
|
command = if attributes_or_command.kind_of? self
|
139
|
+
raise ArgumentError, "cannot pass dependencies with already initialized command" if dependencies.present?
|
109
140
|
attributes_or_command
|
110
141
|
else
|
111
|
-
new(attributes_or_command)
|
142
|
+
new(attributes_or_command, dependencies)
|
112
143
|
end
|
113
144
|
|
114
145
|
command.call &block
|
@@ -137,9 +168,23 @@ module CommandModel
|
|
137
168
|
# Accepts a parameters hash or another of the same class. If another
|
138
169
|
# instance of the same class is passed in then the parameters are copied
|
139
170
|
# to the new object.
|
140
|
-
def initialize(parameters={})
|
171
|
+
def initialize(parameters={}, dependencies={})
|
141
172
|
@type_conversion_errors = {}
|
142
173
|
set_parameters parameters
|
174
|
+
|
175
|
+
dependencies = dependencies.symbolize_keys
|
176
|
+
self.class.dependencies.each do |dependency|
|
177
|
+
value = dependencies.fetch(dependency.name, dependency.default.call)
|
178
|
+
if value.blank? && !dependency.allow_blank
|
179
|
+
raise ArgumentError, "Dependency #{dependency.name} cannot be blank"
|
180
|
+
end
|
181
|
+
self.send "#{dependency.name}=", dependencies.fetch(dependency.name, dependency.default.call)
|
182
|
+
end
|
183
|
+
|
184
|
+
unknown_dependencies = dependencies.keys - self.class.dependencies.map(&:name)
|
185
|
+
if unknown_dependencies.present?
|
186
|
+
raise ArgumentError, "Unknown dependencies: #{bad_dependencies.join(", ")}"
|
187
|
+
end
|
143
188
|
end
|
144
189
|
|
145
190
|
# Executes the command by calling the method +execute+ if the validations
|
data/spec/convert_spec.rb
CHANGED
@@ -30,7 +30,7 @@ describe "CommandModel::Convert" do
|
|
30
30
|
expect(subject.("")).to eq(nil)
|
31
31
|
end
|
32
32
|
|
33
|
-
it "raises
|
33
|
+
it "raises ConvertError when invalid string" do
|
34
34
|
expect { subject.("asdf") }.to raise_error(CommandModel::Convert::ConvertError)
|
35
35
|
expect { subject.("0.1") }.to raise_error(CommandModel::Convert::ConvertError)
|
36
36
|
end
|
@@ -52,7 +52,7 @@ describe "CommandModel::Convert" do
|
|
52
52
|
expect(subject.("")).to eq(nil)
|
53
53
|
end
|
54
54
|
|
55
|
-
it "raises
|
55
|
+
it "raises ConvertError when invalid string" do
|
56
56
|
expect { subject.("asdf") }.to raise_error(CommandModel::Convert::ConvertError)
|
57
57
|
end
|
58
58
|
end
|
@@ -81,7 +81,7 @@ describe "CommandModel::Convert" do
|
|
81
81
|
expect(subject.("")).to eq(nil)
|
82
82
|
end
|
83
83
|
|
84
|
-
it "raises
|
84
|
+
it "raises ConvertError when invalid string" do
|
85
85
|
expect { subject.("asdf") }.to raise_error(CommandModel::Convert::ConvertError)
|
86
86
|
end
|
87
87
|
end
|
@@ -93,6 +93,7 @@ describe "CommandModel::Convert" do
|
|
93
93
|
expect(subject.("01/01/2000")).to eq(Date.civil(2000,1,1))
|
94
94
|
expect(subject.("1/1/2000")).to eq(Date.civil(2000,1,1))
|
95
95
|
expect(subject.("2000-01-01")).to eq(Date.civil(2000,1,1))
|
96
|
+
expect(subject.("29000-01-01")).to eq(Date.civil(29000,1,1))
|
96
97
|
end
|
97
98
|
|
98
99
|
it "returns existing date unchanged" do
|
@@ -108,7 +109,7 @@ describe "CommandModel::Convert" do
|
|
108
109
|
expect(subject.("")).to eq(nil)
|
109
110
|
end
|
110
111
|
|
111
|
-
it "raises
|
112
|
+
it "raises ConvertError when invalid string" do
|
112
113
|
expect { subject.("asdf") }.to raise_error(CommandModel::Convert::ConvertError)
|
113
114
|
expect { subject.("3/50/1290") }.to raise_error(CommandModel::Convert::ConvertError)
|
114
115
|
end
|
data/spec/model_spec.rb
CHANGED
@@ -6,7 +6,7 @@ class ExampleCommand < CommandModel::Model
|
|
6
6
|
end
|
7
7
|
|
8
8
|
describe CommandModel::Model do
|
9
|
-
let(:example_command) { ExampleCommand.new :
|
9
|
+
let(:example_command) { ExampleCommand.new name: "John" }
|
10
10
|
let(:invalid_example_command) { ExampleCommand.new }
|
11
11
|
|
12
12
|
describe "self.parameter" do
|
@@ -38,7 +38,7 @@ describe CommandModel::Model do
|
|
38
38
|
end
|
39
39
|
|
40
40
|
it "accepts multiple attributes with convert" do
|
41
|
-
klass.parameter :foo, :bar, :
|
41
|
+
klass.parameter :foo, :bar, convert: :integer
|
42
42
|
expect(klass.new.methods).to include(:foo)
|
43
43
|
expect(klass.new.methods).to include(:foo=)
|
44
44
|
expect(klass.new.methods).to include(:bar)
|
@@ -46,7 +46,7 @@ describe CommandModel::Model do
|
|
46
46
|
end
|
47
47
|
|
48
48
|
it "accepts multiple attributes with validation" do
|
49
|
-
klass.parameter :foo, :bar, :
|
49
|
+
klass.parameter :foo, :bar, presence: true
|
50
50
|
expect(klass.new.methods).to include(:foo)
|
51
51
|
expect(klass.new.methods).to include(:foo=)
|
52
52
|
expect(klass.new.methods).to include(:bar)
|
@@ -72,6 +72,27 @@ describe CommandModel::Model do
|
|
72
72
|
expect(instance).to_not be_valid
|
73
73
|
expect(instance.errors[:name]).to be_present
|
74
74
|
end
|
75
|
+
|
76
|
+
it "works when model is inherited" do
|
77
|
+
klass.parameter :foo
|
78
|
+
expect(klass.parameters.map(&:name)).to eq([:foo])
|
79
|
+
|
80
|
+
klass_b = Class.new(klass)
|
81
|
+
expect(klass_b.parameters.map(&:name)).to eq([:foo])
|
82
|
+
klass_b.parameter :bar
|
83
|
+
expect(klass.parameters.map(&:name)).to eq([:foo])
|
84
|
+
expect(klass_b.parameters.map(&:name)).to eq([:foo, :bar])
|
85
|
+
|
86
|
+
klass_c = Class.new(klass_b)
|
87
|
+
expect(klass.parameters.map(&:name)).to eq([:foo])
|
88
|
+
expect(klass_b.parameters.map(&:name)).to eq([:foo, :bar])
|
89
|
+
expect(klass_c.parameters.map(&:name)).to eq([:foo, :bar])
|
90
|
+
|
91
|
+
klass_c.parameter :baz
|
92
|
+
expect(klass.parameters.map(&:name)).to eq([:foo])
|
93
|
+
expect(klass_b.parameters.map(&:name)).to eq([:foo, :bar])
|
94
|
+
expect(klass_c.parameters.map(&:name)).to eq([:foo, :bar, :baz])
|
95
|
+
end
|
75
96
|
end
|
76
97
|
|
77
98
|
describe "self.parameters" do
|
@@ -89,13 +110,65 @@ describe CommandModel::Model do
|
|
89
110
|
end
|
90
111
|
end
|
91
112
|
|
113
|
+
describe "self.dependency" do
|
114
|
+
let(:klass) { Class.new(CommandModel::Model) }
|
115
|
+
|
116
|
+
it "creates an attribute reader" do
|
117
|
+
klass.dependency :foo, allow_blank: true
|
118
|
+
expect(klass.new.methods).to include(:foo)
|
119
|
+
end
|
120
|
+
|
121
|
+
it "accepts multiple attributes" do
|
122
|
+
klass.dependency :foo, :bar, allow_blank: true
|
123
|
+
expect(klass.new.methods).to include(:foo)
|
124
|
+
expect(klass.new.methods).to include(:bar)
|
125
|
+
end
|
126
|
+
|
127
|
+
it "accepts multiple attributes with default" do
|
128
|
+
klass.dependency :foo, :bar, default: -> { "baz" }
|
129
|
+
expect(klass.new.methods).to include(:foo)
|
130
|
+
expect(klass.new.methods).to include(:bar)
|
131
|
+
end
|
132
|
+
|
133
|
+
it "works when model is inherited" do
|
134
|
+
klass.dependency :foo
|
135
|
+
expect(klass.dependencies.map(&:name)).to eq([:foo])
|
136
|
+
|
137
|
+
klass_b = Class.new(klass)
|
138
|
+
expect(klass_b.dependencies.map(&:name)).to eq([:foo])
|
139
|
+
klass_b.dependency :bar
|
140
|
+
expect(klass.dependencies.map(&:name)).to eq([:foo])
|
141
|
+
expect(klass_b.dependencies.map(&:name)).to eq([:foo, :bar])
|
142
|
+
|
143
|
+
klass_c = Class.new(klass_b)
|
144
|
+
expect(klass.dependencies.map(&:name)).to eq([:foo])
|
145
|
+
expect(klass_b.dependencies.map(&:name)).to eq([:foo, :bar])
|
146
|
+
expect(klass_c.dependencies.map(&:name)).to eq([:foo, :bar])
|
147
|
+
|
148
|
+
klass_c.dependency :baz
|
149
|
+
expect(klass.dependencies.map(&:name)).to eq([:foo])
|
150
|
+
expect(klass_b.dependencies.map(&:name)).to eq([:foo, :bar])
|
151
|
+
expect(klass_c.dependencies.map(&:name)).to eq([:foo, :bar, :baz])
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
describe "self.dependencies" do
|
156
|
+
it "returns all dependencies in class" do
|
157
|
+
klass = Class.new(CommandModel::Model)
|
158
|
+
klass.dependency :foo
|
159
|
+
klass.dependency :bar
|
160
|
+
|
161
|
+
expect(klass.dependencies.map(&:name)).to eq([:foo, :bar])
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
92
165
|
describe "self.execute" do
|
93
166
|
it "accepts object of same kind and returns it" do
|
94
167
|
expect(ExampleCommand.execute(example_command) {}).to eq(example_command)
|
95
168
|
end
|
96
169
|
|
97
170
|
it "accepts attributes, creates object, and returns it" do
|
98
|
-
c = ExampleCommand.execute(:
|
171
|
+
c = ExampleCommand.execute(name: "John") {}
|
99
172
|
expect(c).to be_kind_of(ExampleCommand)
|
100
173
|
expect(c.name).to eq("John")
|
101
174
|
end
|
@@ -129,6 +202,25 @@ describe CommandModel::Model do
|
|
129
202
|
|
130
203
|
expect(example_command).to_not be_success
|
131
204
|
end
|
205
|
+
|
206
|
+
it "uses default dependencies when not provided" do
|
207
|
+
klass = Class.new(CommandModel::Model)
|
208
|
+
klass.dependency :stdout, default: -> { $stdout }
|
209
|
+
klass.parameter :name
|
210
|
+
m = klass.execute(name: "John")
|
211
|
+
expect(m.stdout).to eq($stdout)
|
212
|
+
expect(m.execution_attempted?).to eq(true)
|
213
|
+
end
|
214
|
+
|
215
|
+
it "accepts dependencies from arguments" do
|
216
|
+
klass = Class.new(CommandModel::Model)
|
217
|
+
klass.dependency :stdout, default: -> { $stdout }
|
218
|
+
klass.parameter :name
|
219
|
+
writer = StringIO.new
|
220
|
+
m = klass.execute({name: "John"}, stdout: writer)
|
221
|
+
expect(m.stdout).to eq(writer)
|
222
|
+
expect(m.execution_attempted?).to eq(true)
|
223
|
+
end
|
132
224
|
end
|
133
225
|
|
134
226
|
describe "self.success" do
|
@@ -151,15 +243,46 @@ describe CommandModel::Model do
|
|
151
243
|
|
152
244
|
describe "initialize" do
|
153
245
|
it "assigns parameters from hash" do
|
154
|
-
m = ExampleCommand.new :
|
246
|
+
m = ExampleCommand.new name: "John"
|
155
247
|
expect(m.name).to eq("John")
|
156
248
|
end
|
157
249
|
|
158
250
|
it "assigns parameters from other CommandModel" do
|
159
|
-
other = ExampleCommand.new :
|
251
|
+
other = ExampleCommand.new name: "John"
|
160
252
|
m = ExampleCommand.new other
|
161
253
|
expect(m.name).to eq(other.name)
|
162
254
|
end
|
255
|
+
|
256
|
+
it "assigns default dependencies when not provided" do
|
257
|
+
klass = Class.new(CommandModel::Model)
|
258
|
+
klass.dependency :stdout, default: -> { $stdout }
|
259
|
+
klass.parameter :name
|
260
|
+
m = klass.new name: "John"
|
261
|
+
expect(m.stdout).to eq($stdout)
|
262
|
+
end
|
263
|
+
|
264
|
+
it "assigns dependencies from arguments" do
|
265
|
+
klass = Class.new(CommandModel::Model)
|
266
|
+
klass.dependency :stdout, default: -> { $stdout }
|
267
|
+
klass.parameter :name
|
268
|
+
writer = StringIO.new
|
269
|
+
m = klass.new({name: "John"}, stdout: writer)
|
270
|
+
expect(m.stdout).to eq(writer)
|
271
|
+
end
|
272
|
+
|
273
|
+
it "raises error when dependency is missing" do
|
274
|
+
klass = Class.new(CommandModel::Model)
|
275
|
+
klass.dependency :stdout
|
276
|
+
klass.parameter :name
|
277
|
+
expect { klass.new name: "John" }.to raise_error(StandardError)
|
278
|
+
end
|
279
|
+
|
280
|
+
it "does not raise error when allow blank dependency is missing" do
|
281
|
+
klass = Class.new(CommandModel::Model)
|
282
|
+
klass.dependency :stdout, allow_blank: true
|
283
|
+
klass.parameter :name
|
284
|
+
expect { klass.new name: "John" }.to_not raise_error
|
285
|
+
end
|
163
286
|
end
|
164
287
|
|
165
288
|
describe "call" do
|