subroutine 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 28f40979839b106e9e9c4d4714815f29c32cc2bd
4
- data.tar.gz: 5f7724cd96e176c19ed230ca410fcb7ed55d577f
3
+ metadata.gz: 212d37192891dfad2e6fced663590d50f37302ee
4
+ data.tar.gz: 2ded356bfcfe49f9b697aba9784325fe2ce4426a
5
5
  SHA512:
6
- metadata.gz: 670db3c5d3b73bc2791b1c38bf1eabd117d319df84fa5f392daf44698d4b759b8bfd20b465efaf06aafb966618fa0ae679a4fa3ffa39b67aad0a9daeec032ccc
7
- data.tar.gz: e76615aaed90eaeafd518c32865bdf9338c40e80c90332a0eca932d510bd80e271d95b69fe43b56e37fd0a229348d9ba74f8660acf009f6f5ea0ee3440243c5b
6
+ metadata.gz: b4dc8ba20210de9eb5d2260f5cc98f95fe6a9c74e9a0ee625434a683a1773273efdc5461e2356238ca63bd7457c9554748f35fecad40a2153b665b81953ac5d1
7
+ data.tar.gz: cf30411572f31668031cc96ac76cb0ce4edb6132b22f9990a38023d32e312b53468179a31dea8604e25e54e0ac69189a7df13f338559c000d8980bb4aada2a2e
data/README.md CHANGED
@@ -154,9 +154,26 @@ class MyOp < ::Subroutine::Op
154
154
  end
155
155
  ```
156
156
 
157
+ Since ops can use other ops, sometimes it's nice to explicitly state the inputs are valid. To "inherit" all the inputs from another op, simply use `inputs_from`.
158
+
159
+ ```ruby
160
+ class MyOp < ::Subroutine::Op
161
+ string :token
162
+ inputs_from MyOtherOp
163
+
164
+ protected
165
+
166
+ def perform
167
+ verify_token!
168
+ MyOtherOp.submit! params.except(:token)
169
+ end
170
+
171
+ end
172
+ ```
173
+
157
174
  #### Validations
158
175
 
159
- Since Ops inlcude ActiveModel::Model, validations can be used just like any other ActiveModel object.
176
+ Since Ops include ActiveModel::Model, validations can be used just like any other ActiveModel object.
160
177
 
161
178
  ```ruby
162
179
  class MyOp < ::Subroutine::Op
data/lib/subroutine/op.rb CHANGED
@@ -96,15 +96,12 @@ module Subroutine
96
96
 
97
97
  def #{field_name}=(v)
98
98
  config = #{field_name}_config
99
- @#{field_name} = type_caster.cast(v, config[:type])
99
+ v = type_caster.cast(v, config[:type])
100
+ @params["#{field_name}"] = v
100
101
  end
101
102
 
102
103
  def #{field_name}
103
- return @#{field_name} if defined?(@#{field_name})
104
- config = #{field_name}_config
105
- deflt = config[:default]
106
- deflt = deflt.call if deflt.respond_to?(:call)
107
- type_caster.cast(deflt, config[:type])
104
+ @params["#{field_name}"]
108
105
  end
109
106
 
110
107
  def #{field_name}_config
@@ -137,7 +134,7 @@ module Subroutine
137
134
 
138
135
  def initialize(inputs = {})
139
136
  @original_params = inputs.with_indifferent_access
140
- @params = {}
137
+ @params = sanitize_params(@original_params)
141
138
  end
142
139
 
143
140
  def errors
@@ -154,10 +151,6 @@ module Subroutine
154
151
  # the action which should be invoked upon form submission (from the controller)
155
152
  def submit
156
153
  observe_submission do
157
- @params = filter_params(@original_params)
158
-
159
- set_accessors(@params)
160
-
161
154
  validate_and_perform
162
155
  end
163
156
 
@@ -173,15 +166,6 @@ module Subroutine
173
166
 
174
167
  protected
175
168
 
176
- # ensure that our type caster has the opportunity to cast each key
177
- def params
178
- out = {}
179
- @params.keys.each do |k|
180
- out[k] = send(k)
181
- end
182
- out
183
- end
184
-
185
169
  def type_caster
186
170
  @type_caster ||= ::Subroutine::TypeCaster.new
187
171
  end
@@ -247,15 +231,19 @@ module Subroutine
247
231
 
248
232
  # if you want to use strong parameters or something in your form object you can do so here.
249
233
  # by default we just slice the inputs to the defined fields
250
- def filter_params(inputs)
251
- inputs.slice(*_fields.keys)
252
- end
253
-
254
-
255
- def set_accessors(inputs)
256
- inputs.each do |key, value|
257
- send("#{key}=", value) if respond_to?("#{key}=")
234
+ def sanitize_params(inputs)
235
+ out = {}.with_indifferent_access
236
+ self._fields.each_pair do |field, config|
237
+ if inputs.has_key?(field)
238
+ out[field] = type_caster.cast(inputs[field], config[:type])
239
+ elsif config[:default]
240
+ deflt = config[:default]
241
+ deflt = deflt.call if deflt.respond_to?(:call)
242
+ out[field] = type_caster.cast(deflt, config[:type])
243
+ end
258
244
  end
245
+
246
+ out
259
247
  end
260
248
 
261
249
  end
@@ -1,5 +1,6 @@
1
1
  require 'date'
2
2
  require 'time'
3
+ require 'bigdecimal'
3
4
  require 'active_support/core_ext/object/blank'
4
5
  require 'active_support/core_ext/object/try'
5
6
  require 'active_support/core_ext/array/wrap'
@@ -10,7 +11,8 @@ module Subroutine
10
11
 
11
12
  TYPES = {
12
13
  :integer => [:int, :integer, :epoch],
13
- :number => [:number, :float, :decimal],
14
+ :number => [:number, :float],
15
+ :decimal => [:decimal, :big_decimal],
14
16
  :string => [:string, :text],
15
17
  :boolean => [:bool, :boolean],
16
18
  :iso_date => [:iso_date],
@@ -29,7 +31,10 @@ module Subroutine
29
31
  when *TYPES[:integer]
30
32
  cast_number(value).try(:to_i)
31
33
  when *TYPES[:number]
32
- cast_number(value)
34
+ cast_number(value).try(:to_f)
35
+ when *TYPES[:decimal]
36
+ d = cast_number(value)
37
+ d ? BigDecimal(d.to_s) : nil
33
38
  when *TYPES[:string]
34
39
  cast_string(value)
35
40
  when *TYPES[:boolean]
@@ -57,7 +62,7 @@ module Subroutine
57
62
  def cast_number(value)
58
63
  val = cast_string(value).strip
59
64
  return nil if val.blank?
60
- val.to_f
65
+ val
61
66
  end
62
67
 
63
68
  def cast_string(value)
@@ -1,8 +1,8 @@
1
1
  module Subroutine
2
2
 
3
3
  MAJOR = 0
4
- MINOR = 1
5
- PATCH = 4
4
+ MINOR = 2
5
+ PATCH = 0
6
6
  PRE = nil
7
7
 
8
8
  VERSION = [MAJOR, MINOR, PATCH, PRE].compact.join('.')
@@ -144,5 +144,29 @@ module Subroutine
144
144
  assert_equal [], op.errors[:whatever]
145
145
  end
146
146
 
147
+ def test_it_sets_the_params_immediately_and_includes_defaults
148
+ op = ::AdminSignupOp.new(email: "foo")
149
+ assert_equal({
150
+ "priveleges" => "min",
151
+ "email" => "foo"
152
+ }, op.params)
153
+ end
154
+
155
+ def test_it_overrides_defaults_with_nils
156
+ op = ::AdminSignupOp.new(email: "foo", priveleges: nil)
157
+ assert_equal({
158
+ "priveleges" => nil,
159
+ "email" => "foo"
160
+ }, op.params)
161
+ end
162
+
163
+ def test_it_casts_params_on_the_way_in
164
+ op = ::TypeCastOp.new(integer_input: "25")
165
+ assert_equal(25, op.params["integer_input"])
166
+
167
+ op.decimal_input = "25.3"
168
+ assert_equal(BigDecimal("25.3"), op.params["decimal_input"])
169
+ end
170
+
147
171
  end
148
172
  end
@@ -115,8 +115,8 @@ module Subroutine
115
115
  op.object_input = {foo: 'bar'}
116
116
  assert_equal({'foo' => 'bar'}, op.object_input)
117
117
 
118
- op.object_input = {"foo" => {:bar => :baz}}
119
- assert_equal({"foo" => {:bar => :baz}}, op.object_input)
118
+ op.object_input = {"foo" => {"bar" => :baz}}
119
+ assert_equal({"foo" => {"bar" => :baz}}, op.object_input)
120
120
  end
121
121
 
122
122
  def test_array_inputs
@@ -132,8 +132,8 @@ module Subroutine
132
132
  op.array_input = ['foo']
133
133
  assert_equal ['foo'], op.array_input
134
134
 
135
- op.array_input = {:bar => true}
136
- assert_equal [{:bar => true}], op.array_input
135
+ op.array_input = {"bar" => true}
136
+ assert_equal [{"bar" => true}], op.array_input
137
137
  end
138
138
 
139
139
  def test_date_inputs
data/test/support/ops.rb CHANGED
@@ -98,6 +98,7 @@ class TypeCastOp < ::Subroutine::Op
98
98
 
99
99
  integer :integer_input
100
100
  number :number_input
101
+ decimal :decimal_input
101
102
  string :string_input
102
103
  boolean :boolean_input
103
104
  date :date_input
metadata CHANGED
@@ -1,83 +1,83 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: subroutine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Nelson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-03 00:00:00.000000000 Z
11
+ date: 2016-08-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - '>='
18
18
  - !ruby/object:Gem::Version
19
19
  version: 4.0.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - '>='
25
25
  - !ruby/object:Gem::Version
26
26
  version: 4.0.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ~>
32
32
  - !ruby/object:Gem::Version
33
33
  version: '1.7'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ~>
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.7'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ~>
46
46
  - !ruby/object:Gem::Version
47
47
  version: '10.0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ~>
53
53
  - !ruby/object:Gem::Version
54
54
  version: '10.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: minitest
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">="
59
+ - - '>='
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ">="
66
+ - - '>='
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: minitest-reporters
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ">="
73
+ - - '>='
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ">="
80
+ - - '>='
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  description: An interface for creating feature-driven operations.
@@ -87,8 +87,8 @@ executables: []
87
87
  extensions: []
88
88
  extra_rdoc_files: []
89
89
  files:
90
- - ".gitignore"
91
- - ".travis.yml"
90
+ - .gitignore
91
+ - .travis.yml
92
92
  - Gemfile
93
93
  - LICENSE.txt
94
94
  - README.md
@@ -120,17 +120,17 @@ require_paths:
120
120
  - lib
121
121
  required_ruby_version: !ruby/object:Gem::Requirement
122
122
  requirements:
123
- - - ">="
123
+ - - '>='
124
124
  - !ruby/object:Gem::Version
125
125
  version: '0'
126
126
  required_rubygems_version: !ruby/object:Gem::Requirement
127
127
  requirements:
128
- - - ">="
128
+ - - '>='
129
129
  - !ruby/object:Gem::Version
130
130
  version: '0'
131
131
  requirements: []
132
132
  rubyforge_project:
133
- rubygems_version: 2.4.6
133
+ rubygems_version: 2.0.14.1
134
134
  signing_key:
135
135
  specification_version: 4
136
136
  summary: Feature-driven operation objects.