light_form 0.0.1 → 0.0.2

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: 1068ccb3160f2a1059f1aaac07e446ba7e92991d
4
- data.tar.gz: 7cb06749857c28860f558e4bc6cf669aada3680d
3
+ metadata.gz: 378076de26719aab740e5c61065c2f6afd7575bc
4
+ data.tar.gz: 307deab9de929cd38f8709178cdcf759932d84e1
5
5
  SHA512:
6
- metadata.gz: f7b5bf89967dc0b71054bda26b3ad240c7db7126921e9da16bdf99418fbd5d4efe37f0979b787d087cec04b97d05d7b26265805c841cda41a3c4c4a4285d6b63
7
- data.tar.gz: b109b70705d9e2b79e5c97e4b78ecf0df65408825d1289b3ff7f7bbd360db7b739908fffa0a5db875df76028fcc14685369adc10f3f5d5c7f13418f953b9534e
6
+ metadata.gz: 32ac9549f36d5d68f0e238dd54181e79655effba82ec837fcc302b3c70e5a5d6a5737aca5190310fe0c3cf2b1fae46808f7941cb295f8f9f33c06066d6871743
7
+ data.tar.gz: 3a921ca9efefd2d99bfc15335c61bf8c59f22f671328350fa169cadbb02ff538980216917451b89b67bc6ea9520101f1fe259373c97b7150f188e2c672f14ebb
data/lib/light_form.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'light_form/version'
2
+ require 'light_form/property_methods'
3
+ require 'light_form/lash'
2
4
  require 'light_form/form'
3
5
  module LightForm
4
- # Your code goes here...
5
6
  end
@@ -1,74 +1,17 @@
1
- require 'set'
2
1
  require 'active_model'
3
2
 
4
3
  module LightForm
5
4
  class Form
6
5
  include ActiveModel::Model
6
+ include ActiveModel::Serializers::JSON
7
+ include PropertyMethods
7
8
 
8
9
  def initialize(params = {})
9
10
  super(_prepare_params(params))
10
11
  end
11
12
 
12
- class << self
13
- def config
14
- @config ||= {}
15
- end
16
-
17
- def properties(*prop_names)
18
- add_property = method(:_add_property)
19
- prop_names.each(&add_property)
20
- end
21
-
22
- def property(prop_name, options = {}, &_block)
23
- _add_property(prop_name)
24
- _add_property_transform(prop_name, options)
25
- _add_property_validation(prop_name, options[:validates]) if options[:validates]
26
- end
27
-
28
- private
29
-
30
- def _properties_transform
31
- config[:properties_transform] ||= {}
32
- end
33
-
34
- def _properties
35
- config[:properties] ||= Set.new
36
- end
37
-
38
- def _add_property_transform(prop_name, options = {})
39
- transformations = options.slice(:from, :transform_with, :default)
40
- return if transformations.empty?
41
- _properties_transform[prop_name] = transformations
42
- end
43
-
44
- def _add_property(prop_name)
45
- send(:attr_accessor, prop_name) if _properties.add?(prop_name)
46
- end
47
-
48
- def _add_property_validation(prop_name, validation)
49
- validates(prop_name, validation)
50
- end
51
- end
52
-
53
- private
54
-
55
- def _prepare_params(value)
56
- params = value.clone
57
- _prepare_params_keys_and_values!(params)
58
- properties = self.class.config[:properties] || []
59
- params.extract!(*properties)
60
- end
61
-
62
- def _prepare_params_keys_and_values!(params)
63
- properties_from = self.class.config[:properties_transform] || {}
64
- properties_from.each do |key_to, hash|
65
- params[key_to] = params.delete(hash[:from]) if hash[:from]
66
- next params[key_to] = hash[:default] if params[key_to].empty? && hash[:default]
67
- next unless hash[:transform_with]
68
- transformation = hash[:transform_with]
69
- trans_proc = transformation.is_a?(Symbol) ? method(transformation) : transformation
70
- params[key_to] = trans_proc.call(params[key_to])
71
- end
13
+ def to_h(*args)
14
+ as_json(*args)
72
15
  end
73
16
  end
74
17
  end
@@ -0,0 +1,20 @@
1
+ require 'active_model'
2
+
3
+ module LightForm
4
+ class Lash < Hash
5
+ include ActiveModel::Model
6
+ include PropertyMethods
7
+
8
+ def initialize(params = {})
9
+ _prepare_params(params).each_pair { |k, v| self[k.to_sym] = v }
10
+ end
11
+
12
+ def self._add_property(prop_name)
13
+ config[:errors_overriden] = true if prop_name == :errors
14
+ return unless _properties.add?(prop_name)
15
+ define_method(prop_name) { |&block| self.[](prop_name, &block) }
16
+ property_assignment = "#{prop_name}=".to_sym
17
+ define_method(property_assignment) { |value| self.[]=(prop_name, value) }
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,190 @@
1
+ require 'set'
2
+ require 'active_support'
3
+
4
+ module LightForm
5
+ TransformationError = Class.new(StandardError)
6
+ MissingCollectionError = Class.new(StandardError)
7
+ MissingParamError = Class.new(StandardError)
8
+
9
+ module PropertyMethods
10
+ def self.included(base)
11
+ base.extend(ClassMethods)
12
+ end
13
+
14
+ module ClassMethods
15
+ def config
16
+ @config ||= {}
17
+ end
18
+
19
+ def properties(*prop_names)
20
+ add_property = method(:_add_property)
21
+ prop_names.each(&add_property)
22
+ end
23
+
24
+ def property(prop_name, options = {}, &block)
25
+ _add_property(prop_name)
26
+ _add_property_transform(prop_name, options)
27
+ _add_property_validation(prop_name, options[:validates]) if options[:validates]
28
+ _add_property_source(prop_name, &block) if block
29
+ end
30
+
31
+ private
32
+
33
+ def _add_property_source(prop_name, &block)
34
+ klass = Class.new(Lash)
35
+ klass.class_eval("def self.name; \"#{ActiveSupport::Inflector.classify(prop_name)}\"; end")
36
+ klass.class_eval(&block)
37
+ _properties_sources[prop_name] = { class: klass }
38
+ end
39
+
40
+ def _properties_sources
41
+ config[:properties_sources] ||= {}
42
+ end
43
+
44
+ def _properties_transform
45
+ config[:properties_transform] ||= {}
46
+ end
47
+
48
+ def _properties
49
+ config[:properties] ||= Set.new
50
+ end
51
+
52
+ def _add_property_transform(prop_name, options = {})
53
+ transformations = options.slice(:from, :transform_with, :with, :default, :model, :collection, :uniq, :required)
54
+ return if transformations.empty?
55
+ _properties_transform[prop_name] = transformations
56
+ end
57
+
58
+ def _add_property(prop_name)
59
+ config[:errors_overriden] = true if prop_name == :errors
60
+ send(:attr_accessor, prop_name) if _properties.add?(prop_name)
61
+ end
62
+
63
+ def _add_property_validation(prop_name, validation)
64
+ validates(prop_name, validation)
65
+ end
66
+ end
67
+
68
+ def _errors
69
+ @_errors
70
+ end
71
+
72
+ def errors_overriden?
73
+ self.class.config[:errors_overriden] == true
74
+ end
75
+
76
+ def valid?
77
+ return (_check_validation && super) unless errors_overriden?
78
+ @_errors = @errors
79
+ @errors = ActiveModel::Errors.new(self)
80
+ stored_method = method(:errors)
81
+ errors_method = -> { @errors }
82
+ define_singleton_method(:errors) { errors_method.call }
83
+ result, store, @_errors, @errors = (_check_validation && super), @_errors, @errors, store
84
+ define_singleton_method(:errors) { stored_method.call }
85
+ result
86
+ end
87
+
88
+ private
89
+
90
+ def _validation_errors(obj)
91
+ obj.errors if obj.respond_to?(:valid?) && !obj.valid?
92
+ end
93
+
94
+ def _check_validation
95
+ @errors = ActiveModel::Errors.new(self)
96
+ properties = _properties.delete(_properties_sources.keys)
97
+ properties.each do |prop|
98
+ public_send(prop).tap do |subject|
99
+ items = subject.is_a?(Array) ? subject.map(&method(:_validation_errors)).compact : _validation_errors(subject)
100
+ @errors.add(prop, items) if items && !items.empty?
101
+ end
102
+ end
103
+ _properties_sources.each do |prop, v|
104
+ next unless v[:params]
105
+ subject = v[:params].clone
106
+ items = subject.is_a?(Array) ? subject.map(&method(:_validation_errors)) : _validation_errors(v[:params])
107
+ @errors.add(prop, items) if items && !items.empty?
108
+ end
109
+ @errors.empty?
110
+ end
111
+
112
+ def _properties_sources
113
+ @_properties_sources ||= self.class.config[:properties_sources] || {}
114
+ end
115
+
116
+ def _properties
117
+ @_properties ||= self.class.config[:properties] || []
118
+ end
119
+
120
+ def _prepare_params(value)
121
+ return if value.nil?
122
+ params = value.clone.symbolize_keys
123
+ return params if _properties.empty?
124
+ _prepare_sources(params)
125
+ _prepare_params_keys_and_values!(params)
126
+ params.extract!(*_properties)
127
+ end
128
+
129
+ def _prepare_params_keys_and_values!(params)
130
+ properties_from = self.class.config[:properties_transform] || {}
131
+ properties_from.clone.each do |key_to, hash|
132
+ _update_key!(params, key_to, hash)
133
+ fail(MissingParamError, key_to.to_s) if hash[:required] && !params.key?(key_to)
134
+ set_default = (params[key_to].nil? || params[key_to].empty?) && hash[:default]
135
+ _update_value_as_default!(params, key_to, hash) if set_default
136
+ _transform_value!(params, key_to, hash) unless set_default
137
+ _modelable_value!(params, key_to, hash)
138
+ _collectionaize_value!(params, key_to, hash)
139
+ end
140
+ end
141
+
142
+ def _update_key!(params, key, hash)
143
+ params[key] = params.delete(hash[:from]) if hash[:from]
144
+ end
145
+
146
+ def _update_value_as_default!(params, key, hash)
147
+ params[key] = hash[:default]
148
+ end
149
+
150
+ def _transform_value!(params, key, hash)
151
+ transformation = hash[:with] || hash[:transform_with]
152
+ return unless transformation
153
+ trans_proc = transformation.is_a?(Symbol) ? method(transformation) : transformation
154
+ params[key] = trans_proc.call(params[key])
155
+ rescue => e
156
+ raise TransformationError, "key #{key}: #{e.message}"
157
+ end
158
+
159
+ def _modelable_value!(params, key, hash)
160
+ return unless hash[:model]
161
+ _save_source_params(key, params[key])
162
+ params[key] = hash[:model].new(params[key])
163
+ end
164
+
165
+ def _save_source_params(key, params)
166
+ _properties_sources[key][:params] = params.clone if _properties_sources[key]
167
+ end
168
+
169
+ def _collectionaize_value!(params, key, hash)
170
+ return unless hash[:collection]
171
+ array = params[key]
172
+ fail(MissingCollectionError, "on key: #{key}") unless array.is_a? Array
173
+ array.uniq! if hash[:uniq]
174
+ return params[key] = array if hash[:collection] == true
175
+ _save_source_params(key, array.compact)
176
+ params[key] = array.compact.map { |source| hash[:collection].new(source) }
177
+ end
178
+
179
+ def _prepare_sources(params)
180
+ _properties_sources.each do |k, v|
181
+ next unless params[k]
182
+ params[k] = params[k].is_a?(Array) ? params[k].map { |s| v[:class].new(s) } : v[:class].new(params[k])
183
+ end
184
+ end
185
+
186
+ def attributes
187
+ OpenStruct.new(keys: self.class.config[:properties])
188
+ end
189
+ end
190
+ end
@@ -1,3 +1,3 @@
1
1
  module LightForm
2
- VERSION = '0.0.1'
2
+ VERSION = '0.0.2'
3
3
  end
data/light_form.gemspec CHANGED
@@ -18,6 +18,7 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ['lib']
20
20
 
21
+ spec.add_runtime_dependency 'activesupport', '>= 3.0.2'
21
22
  spec.add_runtime_dependency 'activemodel', '>= 3.0.2'
22
23
  spec.add_development_dependency 'bundler', '>= 1.6'
23
24
  spec.add_development_dependency 'rake', '~> 10.4'
@@ -1,4 +1,20 @@
1
1
  describe LightForm::Form do
2
+ class ChildModel
3
+ include ActiveModel::Model
4
+ attr_accessor :name, :age
5
+ def equality_state
6
+ [:name, :age].map { |attr| public_send("#{attr}") }
7
+ end
8
+
9
+ def ==(o)
10
+ eql?(o)
11
+ end
12
+
13
+ def eql?(o)
14
+ o.class == self.class && o.equality_state == equality_state
15
+ end
16
+ end
17
+
2
18
  context '.properties' do
3
19
  subject do
4
20
  class_factory do
@@ -68,6 +84,19 @@ describe LightForm::Form do
68
84
  end
69
85
  end
70
86
 
87
+ context 'add with :default and :with option' do
88
+ let(:time) { Time.parse('2015-03-29 14:41:28 +0200') }
89
+ subject do
90
+ object_factory(attributes: { time: '' }) do
91
+ property :time, default: Time.parse('2015-03-29 14:41:28 +0200'), with: -> (v) { Time.parse(v) }
92
+ end
93
+ end
94
+
95
+ it 'assign property value from key :default when value is empty and skip :transform_with' do
96
+ expect(subject.time).to eq(time)
97
+ end
98
+ end
99
+
71
100
  context 'add with :transform_with option assign property value after transformation' do
72
101
  it 'by proc' do
73
102
  test_obj = object_factory(attributes: { number: '12' }) do
@@ -90,6 +119,28 @@ describe LightForm::Form do
90
119
  end
91
120
  end
92
121
 
122
+ context 'add with :with option assign property value after transformation' do
123
+ it 'by proc' do
124
+ test_obj = object_factory(attributes: { number: '12' }) do
125
+ property :number, with: -> (v) { v.to_i }
126
+ end
127
+
128
+ expect(test_obj.number).to eq(12)
129
+ end
130
+
131
+ it 'by method' do
132
+ test_obj = object_factory(attributes: { number: '12' }) do
133
+ property :number, with: :convert_to_number
134
+
135
+ def convert_to_number(value)
136
+ value.to_i
137
+ end
138
+ end
139
+
140
+ expect(test_obj.number).to eq(12)
141
+ end
142
+ end
143
+
93
144
  context 'add with :validates option' do
94
145
  subject do
95
146
  object_factory(real_class_name: 'FakeForm', attributes: { name: '' }) do
@@ -102,17 +153,216 @@ describe LightForm::Form do
102
153
  expect(subject.errors.as_json).to eq(name: ["can't be blank"])
103
154
  end
104
155
  end
156
+
157
+ context 'add with :model option' do
158
+ subject do
159
+ object_factory(attributes: { child: { name: 'Tom', age: 2 } }) do
160
+ property :child, model: ChildModel
161
+ end
162
+ end
163
+
164
+ it 'create model for attribute' do
165
+ expect(subject.child).to be_a(ChildModel)
166
+ expect(subject.child.name).to eq('Tom')
167
+ expect(subject.child.age).to eq(2)
168
+ end
169
+ end
170
+
171
+ context 'add with :collection option' do
172
+ it 'raise error when is not a Array' do
173
+ expect {
174
+ object_factory(attributes: { children: { name: 'Tom', age: 2 } }) do
175
+ property :children, collection: true
176
+ end
177
+ }.to raise_error
178
+ end
179
+
180
+ context 'with :model' do
181
+ subject do
182
+ attributes = {
183
+ children: [
184
+ { name: 'Tom', age: 2 },
185
+ { name: 'Emi', age: 4 }
186
+ ]
187
+ }
188
+
189
+ object_factory(attributes: attributes) do
190
+ property :children, collection: ChildModel
191
+ end
192
+ end
193
+
194
+ it 'returns array of models' do
195
+ expect(subject.children.map(&:class)).to eq([ChildModel, ChildModel])
196
+ expect(subject.children.count).to eq(2)
197
+ expect(subject.children.first.name).to eq('Tom')
198
+ expect(subject.children.last.name).to eq('Emi')
199
+ end
200
+ end
201
+
202
+ context 'with :model and :uniq' do
203
+ subject do
204
+ attributes = {
205
+ children: [
206
+ { name: 'Tom', age: 2 },
207
+ { name: 'Tom', age: 2 }
208
+ ]
209
+ }
210
+
211
+ object_factory(attributes: attributes) do
212
+ property :children, collection: ChildModel, uniq: true
213
+ end
214
+ end
215
+
216
+ it 'returns array of models' do
217
+ expect(subject.children.map(&:class)).to eq([ChildModel])
218
+ expect(subject.children.count).to eq(1)
219
+ expect(subject.children.first.name).to eq('Tom')
220
+ end
221
+ end
222
+ end
223
+
224
+ context 'add with :required option' do
225
+ it 'raise MissingParamError when required param missing' do
226
+ expect {
227
+ object_factory { property :abc, required: true }
228
+ }.to raise_error(LightForm::MissingParamError, 'abc')
229
+ end
230
+ end
231
+ end
232
+
233
+ context 'add nested' do
234
+ let(:attributes) do
235
+ {
236
+ ab: {
237
+ cd: {
238
+ child: { age: '1', name: 'pawel', skip: 'av' }
239
+ },
240
+ ef: [
241
+ { age: '31', name: 'Pawel', skip: 'wrong' },
242
+ { age: '32', name: 'Sylwia', skip: 'bad' }
243
+ ],
244
+ gh: [
245
+ { age: '31', name: 'Pawel', skip: 'wrong' },
246
+ { age: '32', name: 'Sylwia', skip: 'bad' },
247
+ { age: '32', name: 'Sylwia', skip: 'bad' }
248
+ ]
249
+ }
250
+ }
251
+ end
252
+
253
+ it 'hold proper structure' do
254
+ test_obj = object_factory(attributes: attributes) do
255
+ property :ab do
256
+ property :cd do
257
+ property :child, model: ChildModel do
258
+ properties :name, :age
259
+ end
260
+ end
261
+
262
+ property :ef, collection: true do
263
+ property :name
264
+ property :age, with: -> (v) { v.to_i }
265
+ end
266
+
267
+ property :gh, collection: ChildModel, uniq: true do
268
+ properties :name, :age
269
+ end
270
+
271
+ property :ij, collection: true, with: -> (v) { (v.nil? || v.empty?) ? [] : v }
272
+ end
273
+ end
274
+
275
+ expect(test_obj.ab).not_to eq(nil)
276
+ expect(test_obj.ab.cd.child).to be_a(ChildModel)
277
+ expect(test_obj.ab.cd.child.age).to eq('1')
278
+ expect(test_obj.ab.cd.child.name).to eq('pawel')
279
+ expect { test_obj.ab.cd.child.skip }.to raise_error
280
+ expect(test_obj.ab.ef[0].name).to eq('Pawel')
281
+ expect(test_obj.ab.ef[0].age).to eq(31)
282
+ expect(test_obj.ab.gh[0]).to be_a(ChildModel)
283
+ expect(test_obj.ab.gh.count).to eq(2)
284
+ expect(test_obj.ab.ij).to eq([])
285
+ end
286
+
287
+ it 'validation works' do
288
+ test_obj = object_factory(
289
+ attributes: {
290
+ test: {
291
+ child: { age: '1', name: '', skip: 'av' },
292
+ children_hash: [
293
+ { age: '31', name: '', skip: 'wrong' },
294
+ { age: '32', name: 'Sylwia', skip: 'bad' }
295
+ ],
296
+ children: [
297
+ { age: '31', name: 'Pawel', skip: 'wrong' },
298
+ { age: '32', name: '', skip: 'bad' },
299
+ { age: '32', name: '', skip: 'bad' }
300
+ ]
301
+ }
302
+ }
303
+ ) do
304
+ property :test do
305
+ property :child, model: ChildModel do
306
+ property :name, validates: { presence: true }
307
+ property :age, validates: { numericality: true }
308
+ end
309
+
310
+ property :children_hash, collection: true do
311
+ property :name, validates: { presence: true }
312
+ property :age, with: -> (v) { v.to_i }
313
+ end
314
+
315
+ property :children, collection: ChildModel, uniq: true do
316
+ property :name, validates: { presence: true }
317
+ property :age, validates: { numericality: true }
318
+ end
319
+ end
320
+ end
321
+
322
+ expect(test_obj.valid?).to eq(false)
323
+ end
324
+
325
+ it 'to_h' do
326
+ test_obj = object_factory(attributes: attributes) do
327
+ property :ab do
328
+ property :cd do
329
+ property :child, model: ChildModel do
330
+ properties :name, :age
331
+ end
332
+ end
333
+
334
+ property :ef, collection: true do
335
+ property :name
336
+ property :age, with: -> (v) { v.to_i }
337
+ end
338
+
339
+ property :gh, collection: ChildModel, uniq: true do
340
+ properties :name, :age
341
+ end
342
+
343
+ property :ij, collection: true, with: -> (v) { (v.nil? || v.empty?) ? [] : v }
344
+ end
345
+ end
346
+
347
+ expect(test_obj.to_h).to eq(
348
+ {
349
+ ab: {
350
+ cd: {
351
+ child: ChildModel.new(age: '1', name: 'pawel')
352
+ },
353
+ ef: [
354
+ { age: 31, name: 'Pawel' },
355
+ { age: 32, name: 'Sylwia' }
356
+ ],
357
+ gh: [
358
+ ChildModel.new(age: '31', name: 'Pawel'),
359
+ ChildModel.new(age: '32', name: 'Sylwia')
360
+ ],
361
+ ij: []
362
+ }
363
+ }
364
+ )
365
+ end
105
366
  end
106
- # context 'add nested' do
107
- # it 'first_level' do
108
- # test_obj = object_factory(attributes: { ab: { cd: 'cd'} }) do
109
- # property :ab do
110
- # property :cd
111
- # end
112
- # end
113
-
114
- # expect(test_obj.ab).to eq(cd: 'cd')
115
- # end
116
- # end
117
367
  end
118
368
  end
@@ -0,0 +1,161 @@
1
+ describe LightForm::Lash do
2
+ context '.properties' do
3
+ subject do
4
+ class_factory do
5
+ properties :ab, :cd
6
+ properties :cd, :ef
7
+ end
8
+ end
9
+
10
+ it 'add attributes' do
11
+ instance = subject.new(ab: 'ab', cd: 'cd', ef: 'ef', skip: 'this')
12
+ expect(instance.ab).to eq('ab')
13
+ expect(instance.cd).to eq('cd')
14
+ expect(instance.ef).to eq('ef')
15
+ expect { instance.skip }.to raise_error(NoMethodError)
16
+ end
17
+ end
18
+
19
+ context 'property' do
20
+ context 'add' do
21
+ it 'new property' do
22
+ test_obj = object_factory(attributes: { ab: 'ab', cd: 'cd', skip: 'this' }) do
23
+ property :ab
24
+ property :cd
25
+ end
26
+
27
+ expect(test_obj.ab).to eq('ab')
28
+ expect(test_obj.cd).to eq('cd')
29
+ expect { test_obj.skip }.to raise_error(NoMethodError)
30
+ end
31
+ end
32
+
33
+ context 'with options' do
34
+ context 'add with :from option' do
35
+ subject do
36
+ object_factory(attributes: { aB: 'ab' }) do
37
+ property :ab, from: :aB
38
+ end
39
+ end
40
+
41
+ it 'assign property value from key provided by :from option' do
42
+ expect(subject.ab).to eq('ab')
43
+ end
44
+ end
45
+
46
+ context 'add with :default option' do
47
+ subject do
48
+ object_factory(attributes: { ab: '' }) do
49
+ property :ab, default: 'Default'
50
+ end
51
+ end
52
+
53
+ it 'assign property value from key provided by :default option when value is empty' do
54
+ expect(subject.ab).to eq('Default')
55
+ end
56
+ end
57
+
58
+ context 'add with :default and :transform_with option' do
59
+ let(:time) { Time.parse('2015-03-29 14:41:28 +0200') }
60
+ subject do
61
+ object_factory(attributes: { time: '' }) do
62
+ property :time, default: Time.parse('2015-03-29 14:41:28 +0200'), transform_with: -> (v) { Time.parse(v) }
63
+ end
64
+ end
65
+
66
+ it 'assign property value from key :default when value is empty and skip :transform_with' do
67
+ expect(subject.time).to eq(time)
68
+ end
69
+ end
70
+
71
+ context 'add with :default and :with option' do
72
+ let(:time) { Time.parse('2015-03-29 14:41:28 +0200') }
73
+ subject do
74
+ object_factory(attributes: { time: '' }) do
75
+ property :time, default: Time.parse('2015-03-29 14:41:28 +0200'), with: -> (v) { Time.parse(v) }
76
+ end
77
+ end
78
+
79
+ it 'assign property value from key :default when value is empty and skip :transform_with' do
80
+ expect(subject.time).to eq(time)
81
+ end
82
+ end
83
+
84
+ context 'add with :transform_with option assign property value after transformation' do
85
+ it 'by proc' do
86
+ test_obj = object_factory(attributes: { number: '12' }) do
87
+ property :number, transform_with: -> (v) { v.to_i }
88
+ end
89
+
90
+ expect(test_obj.number).to eq(12)
91
+ end
92
+
93
+ it 'by method' do
94
+ test_obj = object_factory(attributes: { number: '12' }) do
95
+ property :number, transform_with: :convert_to_number
96
+
97
+ def convert_to_number(value)
98
+ value.to_i
99
+ end
100
+ end
101
+
102
+ expect(test_obj.number).to eq(12)
103
+ end
104
+ end
105
+
106
+ context 'add with :with option assign property value after transformation' do
107
+ it 'by proc' do
108
+ test_obj = object_factory(attributes: { number: '12' }) do
109
+ property :number, with: -> (v) { v.to_i }
110
+ end
111
+
112
+ expect(test_obj.number).to eq(12)
113
+ end
114
+
115
+ it 'by method' do
116
+ test_obj = object_factory(attributes: { number: '12' }) do
117
+ property :number, with: :convert_to_number
118
+
119
+ def convert_to_number(value)
120
+ value.to_i
121
+ end
122
+ end
123
+
124
+ expect(test_obj.number).to eq(12)
125
+ end
126
+ end
127
+
128
+ context 'add with :validates option' do
129
+ subject do
130
+ object_factory(real_class_name: 'FakeHash', attributes: { name: '' }) do
131
+ property :name, validates: { presence: true }
132
+ end
133
+ end
134
+
135
+ it 'attribute has validation' do
136
+ expect(subject.valid?).to eq(false)
137
+ expect(subject.errors.as_json).to eq(name: ["can't be blank"])
138
+ end
139
+ end
140
+ end
141
+
142
+ it 'is a hash' do
143
+ test_obj = object_factory(real_class_name: 'LashTest', attributes: { name: '' }) do
144
+ property :name, validates: { presence: true }
145
+ end
146
+
147
+ expect(test_obj).to eq(name: '')
148
+ end
149
+
150
+ it 'is a hash' do
151
+ test_obj = object_factory(real_class_name: 'LashTest1', attributes: { errors: '' }) do
152
+ property :errors, validates: { presence: true }
153
+ end
154
+ expect(test_obj.valid?).to eq(false)
155
+ expect(test_obj).to eq(errors: '')
156
+ expect(test_obj.errors).to eq('')
157
+ expect(test_obj.errors_overriden?).to eq(true)
158
+ expect(test_obj._errors.as_json).to eq(errors: ["can't be blank"])
159
+ end
160
+ end
161
+ end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: light_form
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pawel Niemczyk
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-29 00:00:00.000000000 Z
11
+ date: 2015-04-01 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 3.0.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 3.0.2
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: activemodel
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -154,9 +168,12 @@ files:
154
168
  - Rakefile
155
169
  - lib/light_form.rb
156
170
  - lib/light_form/form.rb
171
+ - lib/light_form/lash.rb
172
+ - lib/light_form/property_methods.rb
157
173
  - lib/light_form/version.rb
158
174
  - light_form.gemspec
159
175
  - spec/lib/form_spec.rb
176
+ - spec/lib/lash_spec.rb
160
177
  - spec/spec_helper.rb
161
178
  - spec/support/factory_helper.rb
162
179
  homepage: https://github.com/pniemczyk/light_form
@@ -185,5 +202,6 @@ specification_version: 4
185
202
  summary: Light Form
186
203
  test_files:
187
204
  - spec/lib/form_spec.rb
205
+ - spec/lib/lash_spec.rb
188
206
  - spec/spec_helper.rb
189
207
  - spec/support/factory_helper.rb