light_form 0.0.1 → 0.0.2

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 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