light_params 1.0.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 +7 -0
- data/.gitignore +24 -0
- data/.rspec +4 -0
- data/.rubocop.yml +44 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/Guardfile +11 -0
- data/LICENSE.txt +22 -0
- data/README.md +119 -0
- data/Rakefile +6 -0
- data/lib/light_params.rb +8 -0
- data/lib/light_params/errors.rb +9 -0
- data/lib/light_params/lash.rb +36 -0
- data/lib/light_params/lash_builder.rb +68 -0
- data/lib/light_params/properties_configuration.rb +95 -0
- data/lib/light_params/version.rb +3 -0
- data/light_params.gemspec +32 -0
- data/spec/lib/lash_spec.rb +264 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/support/factory_helper.rb +11 -0
- metadata +220 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ab78d1c213fad5ed9a7ca89dd9babee59ce978ca
|
4
|
+
data.tar.gz: 61e3b293e45680ed204d83b4918226b9aa0fd5a8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 91034ea540aa68cc495a7c7181cedf2229d1c01a765920f2e32ded329ef74149889bd4e77a8f148b85686f28a927ec4580ae490427c9edf09d2d3aff3cf1008d
|
7
|
+
data.tar.gz: ef68c27204f2dbf9536804f58555a597b9fbb66c1755ed0d918d2bf0cd82507aea34f09e01ed693ae0d5769b3dd3b6db5495f9917bb4af4bd97e63be84c0b615
|
data/.gitignore
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
23
|
+
.rubocop_todo.yml
|
24
|
+
.ruby-version
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# This configuration was generated by `rubocop --auto-gen-config`
|
2
|
+
# on 2015-02-23 06:17:38 +0100 using RuboCop version 0.27.1.
|
3
|
+
# The point is for the user to remove these configuration records
|
4
|
+
# one by one as the offenses are removed from the code base.
|
5
|
+
# Note that changes in the inspected code, or installation of new
|
6
|
+
# versions of RuboCop, may require this file to be generated again.
|
7
|
+
|
8
|
+
# Offense count: 3
|
9
|
+
Style/Documentation:
|
10
|
+
Enabled: false
|
11
|
+
|
12
|
+
# Offense count: 2
|
13
|
+
# Cop supports --auto-correct.
|
14
|
+
# Configuration parameters: PreferredDelimiters.
|
15
|
+
Style/PercentLiteralDelimiters:
|
16
|
+
Enabled: false
|
17
|
+
|
18
|
+
# Offense count: 1
|
19
|
+
# Cop supports --auto-correct.
|
20
|
+
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
21
|
+
Style/TrailingBlankLines:
|
22
|
+
Enabled: false
|
23
|
+
|
24
|
+
# Offense count: 1
|
25
|
+
# Cop supports --auto-correct.
|
26
|
+
# Configuration parameters: ExactNameMatch, AllowPredicates, AllowDSLWriters, Whitelist.
|
27
|
+
Style/TrivialAccessors:
|
28
|
+
Enabled: false
|
29
|
+
|
30
|
+
# Offense count: 2
|
31
|
+
# Cop supports --auto-correct.
|
32
|
+
Style/UnneededPercentQ:
|
33
|
+
Enabled: false
|
34
|
+
|
35
|
+
Documentation:
|
36
|
+
Enabled: false
|
37
|
+
|
38
|
+
Metrics/LineLength:
|
39
|
+
Max: 120
|
40
|
+
|
41
|
+
AllCops:
|
42
|
+
Exclude:
|
43
|
+
- '**/Guardfile'
|
44
|
+
- '**/light_parmas.gemspec'
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
guard :rspec, cmd: 'rspec' do
|
2
|
+
watch(%r{^lib/(.+).rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
3
|
+
watch(%r{^spec/(.+).rb$}) { |m| "spec/#{m[1]}.rb" }
|
4
|
+
watch('spec/spec_helper.rb') { 'spec' }
|
5
|
+
watch('Gemfile')
|
6
|
+
end
|
7
|
+
|
8
|
+
guard :rubocop, all_on_start: false, cli: ['--format', 'clang'] do
|
9
|
+
watch(%r{.+\.rb$})
|
10
|
+
watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
|
11
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Pawel Niemczyk
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
# LightParams
|
2
|
+
|
3
|
+
https://travis-ci.org/pniemczyk/light_params
|
4
|
+
|
5
|
+
[](http://badge.fury.io/rb/light_params)
|
6
|
+
[](https://travis-ci.org/pniemczyk/light_params)
|
7
|
+
[](https://coveralls.io/r/pniemczyk/light_params)
|
8
|
+
|
9
|
+
This is a better structure for the has. Thanks to this class you can from symbolized/stringify hash extract what you need with proper transformation values and keys.
|
10
|
+
|
11
|
+
## Examples
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
# class Pet
|
15
|
+
class Pet < LightParams::Lash
|
16
|
+
property :name, from: :nickname
|
17
|
+
end
|
18
|
+
|
19
|
+
# class Person
|
20
|
+
class Person < LightParams::Lash
|
21
|
+
properties :first_name, :last_name
|
22
|
+
property :age, with: -> (v) { v.to_i }
|
23
|
+
property :created_at, with: :to_date
|
24
|
+
property :parents, collection: Person, compact: true
|
25
|
+
property :pet, model: Pet
|
26
|
+
property :children, collection: true, uniq: true do
|
27
|
+
properties :first_name, :last_name
|
28
|
+
property :age, with: -> (v) { v.to_i }
|
29
|
+
property :date, from: :created_at, with: :to_date
|
30
|
+
property :sex, default: :unknown
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def to_date(value)
|
36
|
+
DateTime.parse(value)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# hash
|
41
|
+
source = {
|
42
|
+
first_name: 'Pawel',
|
43
|
+
last_name: 'Niemczyk',
|
44
|
+
'age' => '30',
|
45
|
+
'created_at' => '1983-09-07T18:37:52+02:00',
|
46
|
+
pet: {
|
47
|
+
nickname: 'Brutus'
|
48
|
+
},
|
49
|
+
parents: [
|
50
|
+
{
|
51
|
+
first_name: 'Wladyslaw',
|
52
|
+
"last_name" => 'Niemczyk'
|
53
|
+
},
|
54
|
+
nil
|
55
|
+
],
|
56
|
+
children: [
|
57
|
+
{
|
58
|
+
first_name: 'Emilia',
|
59
|
+
'last_name' => 'Niemczyk',
|
60
|
+
age: '4',
|
61
|
+
created_at: '2011-02-11T18:37:52+02:00'
|
62
|
+
},
|
63
|
+
{
|
64
|
+
first_name: 'Tomasz',
|
65
|
+
last_name: 'Niemczyk',
|
66
|
+
'age' => '2',
|
67
|
+
created_at: '2012-06-27T18:37:52+02:00'
|
68
|
+
},
|
69
|
+
{
|
70
|
+
first_name: 'Tomasz',
|
71
|
+
'last_name' => 'Niemczyk',
|
72
|
+
age: '2',
|
73
|
+
created_at: '2012-06-27T18:37:52+02:00'
|
74
|
+
}
|
75
|
+
]
|
76
|
+
}
|
77
|
+
|
78
|
+
person = Person.new(source)
|
79
|
+
|
80
|
+
# date was changed by `from` modificator from `created_at` to `date` and by `with` value was transformed by `:to_date` method
|
81
|
+
person.children.first.date # => `Fri, 11 Feb 2011 18:37:52 +0200`
|
82
|
+
person.children.first.sex # => `:unknown` was set by `default` modificator
|
83
|
+
person.children.first.age # => 4
|
84
|
+
person.children.count # => 2 # children are uniq by `uniq` modificator
|
85
|
+
person.parents.count # => 1 # nil value was removed by `compact` modificator
|
86
|
+
person.parents.first.children # => [] # it is collection so by default empty it will be empty array
|
87
|
+
|
88
|
+
json = source.to_json
|
89
|
+
person_object = Person.from_json(json) # this will recreate person object from json
|
90
|
+
```
|
91
|
+
|
92
|
+
|
93
|
+
## Installation
|
94
|
+
|
95
|
+
Add this line to your application's Gemfile:
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
gem 'light_params'
|
99
|
+
```
|
100
|
+
|
101
|
+
And then execute:
|
102
|
+
|
103
|
+
$ bundle
|
104
|
+
|
105
|
+
Or install it yourself as:
|
106
|
+
|
107
|
+
$ gem install light_params
|
108
|
+
|
109
|
+
## Usage
|
110
|
+
|
111
|
+
TODO: Write usage instructions here
|
112
|
+
|
113
|
+
## Contributing
|
114
|
+
|
115
|
+
1. Fork it ( https://github.com/[my-github-username]/light_params/fork )
|
116
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
117
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
118
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
119
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/lib/light_params.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
module LightParams
|
2
|
+
module Errors
|
3
|
+
BaseError = Class.new(StandardError)
|
4
|
+
ValueTransformationError = Class.new(BaseError)
|
5
|
+
MissingCollectionError = Class.new(BaseError)
|
6
|
+
MissingParamError = Class.new(BaseError)
|
7
|
+
JsonParseError = Class.new(BaseError)
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'active_model'
|
2
|
+
|
3
|
+
module LightParams
|
4
|
+
class Lash < Hash
|
5
|
+
include PropertiesConfiguration
|
6
|
+
include ActiveModel::Serializers::JSON
|
7
|
+
|
8
|
+
def initialize(params = {})
|
9
|
+
LashBuilder.lash_params(self, params).each_pair do |k, v|
|
10
|
+
self[k.to_sym] = v
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.name
|
15
|
+
@name || super
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.from_json(json, include_root = false)
|
19
|
+
hash = JSON.parse(json)
|
20
|
+
hash = hash.values.first if include_root
|
21
|
+
new(hash)
|
22
|
+
rescue => e
|
23
|
+
raise(Errors::JsonParseError, e.message)
|
24
|
+
end
|
25
|
+
|
26
|
+
def attributes
|
27
|
+
OpenStruct.new(keys: self.class.config[:properties])
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def include_root_in_json
|
33
|
+
false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module LightParams
|
2
|
+
class LashBuilder
|
3
|
+
class << self
|
4
|
+
def lash_params(lash, params)
|
5
|
+
prepare_params(lash, params || {})
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def prepare_params(lash, params)
|
11
|
+
properties = lash.class.config[:properties] ||= params.keys.map(&:to_sym)
|
12
|
+
properties_sources = lash.class.config[:properties_sources] || {}
|
13
|
+
properties_modifications = lash.class.config[:properties_modifications] || {}
|
14
|
+
|
15
|
+
{}.tap do |result|
|
16
|
+
properties.each do |key|
|
17
|
+
modification = properties_modifications[key] || {}
|
18
|
+
value = hash_value(params, (modification[:from] || key))
|
19
|
+
raise(MissingParamError, key.to_s) if modification[:required] && value.nil?
|
20
|
+
next result[key] = (modification[:default] || (modification[:collection] ? [] : value)) if value.nil? || value.empty?
|
21
|
+
value = prepare_sources(properties_sources[key], value) if properties_sources[key]
|
22
|
+
value = transform_value(modification[:with], lash, key, value) if modification[:with]
|
23
|
+
next result[key] = modelable_value(modification[:model], value) if modification[:model]
|
24
|
+
next result[key] = collectionaize_value(modification, value, properties_sources[key]) if modification[:collection]
|
25
|
+
result[key] = value
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def hash_value(hash, key)
|
31
|
+
hash[key] || hash[key.to_s]
|
32
|
+
end
|
33
|
+
|
34
|
+
def prepare_sources(source, value)
|
35
|
+
value.is_a?(Array) ? value.map { |s| source[:class].new(s) if s } : source[:class].new(value)
|
36
|
+
end
|
37
|
+
|
38
|
+
def transform_value(transformation, lash, key, value)
|
39
|
+
trans_proc = transformation.is_a?(Proc) ? transformation : lash.method(transformation)
|
40
|
+
trans_proc.call(value)
|
41
|
+
rescue => e
|
42
|
+
raise Errors::ValueTransformationError, "key #{key}: #{e.message}"
|
43
|
+
end
|
44
|
+
|
45
|
+
def modelable_value(model_class, value)
|
46
|
+
# _save_source_params(key, params[key])
|
47
|
+
model_class.new(value)
|
48
|
+
end
|
49
|
+
|
50
|
+
# def _save_source_params(key, params)
|
51
|
+
# _properties_sources[key][:params] = params.clone if _properties_sources[key]
|
52
|
+
# end
|
53
|
+
|
54
|
+
def collectionaize_value(modifications, value, sourced)
|
55
|
+
collection = modifications[:collection]
|
56
|
+
raise(Errors::MissingCollectionError, "on key: #{key}") unless value.is_a? Array
|
57
|
+
value.compact! if modifications[:compact]
|
58
|
+
value.uniq! if modifications[:uniq]
|
59
|
+
if collection == true
|
60
|
+
sourced ? value : value.map { |v| v.is_a?(Hash) ? Lash.new(v) : v }
|
61
|
+
else
|
62
|
+
# _save_source_params(key, array.compact)
|
63
|
+
value.map { |source| collection.new(source) if source }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'active_support'
|
3
|
+
|
4
|
+
module LightParams
|
5
|
+
module PropertiesConfiguration
|
6
|
+
def self.included(base)
|
7
|
+
base.extend(ClassMethods)
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def config
|
12
|
+
@config ||= {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def properties(*prop_names)
|
16
|
+
opts = prop_names.last.is_a?(Hash) ? prop_names.pop : nil
|
17
|
+
prop_names.each do |prop_name|
|
18
|
+
_add_property(prop_name)
|
19
|
+
_add_property_modifications(prop_name, opts || {})
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def property(prop_name, options = {}, &block)
|
24
|
+
_add_property(prop_name)
|
25
|
+
_add_property_modifications(prop_name, options)
|
26
|
+
_add_property_validation(prop_name, options[:validates]) if options[:validates]
|
27
|
+
_add_property_source(prop_name, &block) if block
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def _add_property_source(prop_name, &block)
|
33
|
+
klass = Class.new(self)
|
34
|
+
klass.instance_variable_set(:@config, {})
|
35
|
+
klass.instance_variable_set(:@name, ActiveSupport::Inflector.classify(prop_name))
|
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_modifications
|
45
|
+
config[:properties_modifications] ||= {}
|
46
|
+
end
|
47
|
+
|
48
|
+
def _properties
|
49
|
+
config[:properties] ||= Set.new
|
50
|
+
end
|
51
|
+
|
52
|
+
def _validations
|
53
|
+
config[:validations] ||= {}
|
54
|
+
end
|
55
|
+
|
56
|
+
def _add_property_modifications(prop_name, options = {})
|
57
|
+
modifications = options.slice(:from, :with, :default, :model, :collection, :uniq, :compact, :required)
|
58
|
+
return if modifications.empty?
|
59
|
+
_properties_modifications[prop_name] = modifications
|
60
|
+
end
|
61
|
+
|
62
|
+
def _add_property(prop_name)
|
63
|
+
return unless _properties.add?(prop_name)
|
64
|
+
define_method(prop_name) { |&block| self.[](prop_name, &block) }
|
65
|
+
property_assignment = "#{prop_name}=".to_sym
|
66
|
+
define_method(property_assignment) { |value| self.[]=(prop_name, value) }
|
67
|
+
end
|
68
|
+
|
69
|
+
def _add_property_validation(prop_name, validation)
|
70
|
+
_validations[prop_name] = validation
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def respond_to?(method_name, include_private = false)
|
75
|
+
return _properties.include?(method_name.to_s.delete('=').to_sym) unless super
|
76
|
+
false
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def _properties
|
82
|
+
self.class.config[:properties] || {}
|
83
|
+
end
|
84
|
+
|
85
|
+
def method_missing(method, *args, &block)
|
86
|
+
method_writer = method.to_s[-1] == '='
|
87
|
+
return (method_writer ? self.[]=(method.to_s[-1].to_sym, *args, &block) : self.[](method, *args, &block)) if respond_to?(method)
|
88
|
+
super
|
89
|
+
end
|
90
|
+
|
91
|
+
def attributes
|
92
|
+
OpenStruct.new(keys: _properties)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'light_params/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'light_params'
|
8
|
+
spec.version = LightParams::VERSION
|
9
|
+
spec.authors = ['Pawel Niemczyk']
|
10
|
+
spec.email = ['pniemczyk.info@gmail.com']
|
11
|
+
spec.summary = %q{Light params}
|
12
|
+
spec.description = %q{Light params}
|
13
|
+
spec.homepage = 'https://github.com/pniemczyk/light_params'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = %w(lib)
|
20
|
+
|
21
|
+
spec.add_runtime_dependency 'activesupport', '~> 3.0'
|
22
|
+
spec.add_runtime_dependency 'activemodel', '~> 3.0'
|
23
|
+
spec.add_development_dependency 'ruby_dep', '~> 1.1'
|
24
|
+
spec.add_development_dependency 'bundler', '~> 1.7'
|
25
|
+
spec.add_development_dependency 'rake', '~> 10.4'
|
26
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
27
|
+
spec.add_development_dependency 'guard', '~> 2.12'
|
28
|
+
spec.add_development_dependency 'guard-rspec', '~> 4.5'
|
29
|
+
spec.add_development_dependency 'guard-rubocop', '~> 1.2'
|
30
|
+
spec.add_development_dependency 'coveralls', '~> 0.7'
|
31
|
+
spec.add_development_dependency 'awesome_print', '~> 1.6'
|
32
|
+
end
|
@@ -0,0 +1,264 @@
|
|
1
|
+
describe LightParams::Lash do
|
2
|
+
let(:person_source) do
|
3
|
+
{
|
4
|
+
first_name: 'Pawel',
|
5
|
+
last_name: 'Niemczyk',
|
6
|
+
age: '30',
|
7
|
+
created_at: '1983-09-07T18:37:52+02:00',
|
8
|
+
children: children_source
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:children_source) { [first_child_source, last_child_source] }
|
13
|
+
|
14
|
+
let(:first_child_source) do
|
15
|
+
{
|
16
|
+
first_name: 'Emilia',
|
17
|
+
last_name: 'Niemczyk',
|
18
|
+
age: '4',
|
19
|
+
created_at: '2011-02-11T18:37:52+02:00'
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
let(:last_child_source) do
|
24
|
+
{
|
25
|
+
first_name: 'Tomasz',
|
26
|
+
last_name: 'Niemczyk',
|
27
|
+
age: '2',
|
28
|
+
created_at: '2012-06-27T18:37:52+02:00'
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
subject do
|
33
|
+
object_factory(params: source) do
|
34
|
+
properties :first_name, :last_name
|
35
|
+
property :age, with: -> (v) { v.to_i }
|
36
|
+
property :created_at, with: :to_date
|
37
|
+
property :children, collection: true do
|
38
|
+
properties :first_name, :last_name
|
39
|
+
property :age, with: -> (v) { v.to_i }
|
40
|
+
property :created_at, with: :to_date
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def to_date(value)
|
46
|
+
DateTime.parse(value)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe 'ability to use method instead of []' do
|
52
|
+
subject do
|
53
|
+
object_factory(params: source) do
|
54
|
+
properties :first_name, :last_name
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
let(:source) { person_source }
|
59
|
+
|
60
|
+
it '#first_name returns same value as [:first_name]' do
|
61
|
+
expect(subject.first_name).to eq(subject[:first_name])
|
62
|
+
expect(subject.first_name).to eq(source[:first_name])
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe 'ability to transform value before being assigned' do
|
67
|
+
subject do
|
68
|
+
object_factory(params: source) do
|
69
|
+
properties :first_name, :last_name, with: -> (v) { v.to_i }
|
70
|
+
property :age, with: -> (v) { v.to_i }
|
71
|
+
property :created_at, with: :to_date
|
72
|
+
property :children, collection: true do
|
73
|
+
property :age, with: -> (v) { v.to_i }
|
74
|
+
property :created_at, with: :to_date
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def to_date(value)
|
80
|
+
DateTime.parse(value)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
let(:source) { person_source }
|
87
|
+
|
88
|
+
it '#age returns as int by transformation' do
|
89
|
+
expect(subject.first_name).to eq(0)
|
90
|
+
expect(subject.last_name).to eq(0)
|
91
|
+
expect(subject.age).to eq(source[:age].to_i)
|
92
|
+
expect(subject.created_at).to eq(DateTime.parse(source[:created_at]))
|
93
|
+
expect(subject.children.first.age).to eq(source[:children].first[:age].to_i)
|
94
|
+
expect(subject.children.first.created_at).to eq(DateTime.parse(source[:children].first[:created_at]))
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe 'ability to assign to key from other name of key' do
|
99
|
+
subject do
|
100
|
+
object_factory(params: source) do
|
101
|
+
property :name, from: :first_name
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
let(:source) { person_source }
|
106
|
+
|
107
|
+
it '#name returns as [:first_name] by using from option' do
|
108
|
+
expect(subject.name).to eq(source[:first_name])
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe 'ability to set default value when value is not present' do
|
113
|
+
subject do
|
114
|
+
object_factory(params: source) do
|
115
|
+
property :name, default: 'Andrzej'
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
let(:source) { {} }
|
120
|
+
|
121
|
+
it '#name returns Andrzej by using default option' do
|
122
|
+
expect(subject.name).to eq('Andrzej')
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe 'ability to make uniq collecion' do
|
127
|
+
subject do
|
128
|
+
object_factory(params: source) do
|
129
|
+
property :children, collection: true, uniq: true
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
let(:source) do
|
134
|
+
{
|
135
|
+
children: [
|
136
|
+
first_child_source,
|
137
|
+
first_child_source,
|
138
|
+
last_child_source,
|
139
|
+
last_child_source
|
140
|
+
]
|
141
|
+
}
|
142
|
+
end
|
143
|
+
|
144
|
+
it '#children are returned as uniq' do
|
145
|
+
expect(subject.children.count).to eq(2)
|
146
|
+
expect(subject.children.first.first_name).to eq(first_child_source[:first_name])
|
147
|
+
expect(subject.children.last.first_name).to eq(last_child_source[:first_name])
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe 'ability to clear collection from nil values' do
|
152
|
+
subject do
|
153
|
+
object_factory(params: source) do
|
154
|
+
property :children, collection: true, compact: true
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
let(:source) do
|
159
|
+
{
|
160
|
+
children: [
|
161
|
+
first_child_source,
|
162
|
+
nil,
|
163
|
+
nil,
|
164
|
+
last_child_source
|
165
|
+
]
|
166
|
+
}
|
167
|
+
end
|
168
|
+
|
169
|
+
it '#children are returned as compact' do
|
170
|
+
expect(subject.children.count).to eq(2)
|
171
|
+
expect(subject.children.first.first_name).to eq(first_child_source[:first_name])
|
172
|
+
expect(subject.children.last.first_name).to eq(last_child_source[:first_name])
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
describe 'ability to make instance for defined class from value' do
|
177
|
+
class Child
|
178
|
+
attr_accessor :first_name, :last_name, :age, :created_at
|
179
|
+
def initialize(attrs = {})
|
180
|
+
attrs.each { |k, v| send("#{k}=", v) }
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
subject do
|
185
|
+
object_factory(params: source) do
|
186
|
+
property :child, model: Child
|
187
|
+
property :children, collection: Child
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
let(:source) do
|
192
|
+
{
|
193
|
+
child: first_child_source,
|
194
|
+
children: [
|
195
|
+
first_child_source,
|
196
|
+
last_child_source
|
197
|
+
]
|
198
|
+
}
|
199
|
+
end
|
200
|
+
|
201
|
+
it '#children are returned as compact' do
|
202
|
+
expect(subject.child).to be_kind_of(Child)
|
203
|
+
expect(subject.child.first_name).to eq(first_child_source[:first_name])
|
204
|
+
expect(subject.children.count).to eq(2)
|
205
|
+
expect(subject.children.first).to be_kind_of(Child)
|
206
|
+
expect(subject.children.last).to be_kind_of(Child)
|
207
|
+
expect(subject.children.first.first_name).to eq(first_child_source[:first_name])
|
208
|
+
expect(subject.children.last.first_name).to eq(last_child_source[:first_name])
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
describe '.from_json' do
|
213
|
+
subject do
|
214
|
+
class_factory do
|
215
|
+
properties :first_name, :last_name, :age, :created_at
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'returns instance of lash' do
|
220
|
+
test_obj = subject.from_json(first_child_source.to_json)
|
221
|
+
expect(test_obj).to be_kind_of(described_class)
|
222
|
+
expect(test_obj.first_name).to eq(first_child_source[:first_name])
|
223
|
+
end
|
224
|
+
|
225
|
+
it 'raise JsonParseError when parsing fail' do
|
226
|
+
expect { subject.from_json('abc') }.to raise_error(LightParams::Errors::JsonParseError)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
describe '#to_json' do
|
231
|
+
subject do
|
232
|
+
object_factory(params: first_child_source, real_class_name: 'TestToJson') do
|
233
|
+
properties :first_name, :last_name
|
234
|
+
property :age, with: -> (v) { v.to_i }
|
235
|
+
property :created_at, with: -> (v) { DateTime.parse(v) }
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
it 'returns json' do
|
240
|
+
expect(subject.to_json).to eq(
|
241
|
+
'{"age":4,"created_at":"2011-02-11T18:37:52+02:00","first_name":"Emilia","last_name":"Niemczyk"}'
|
242
|
+
)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
describe '#as_json' do
|
247
|
+
subject do
|
248
|
+
object_factory(params: first_child_source, real_class_name: 'TestAsJson') do
|
249
|
+
properties :first_name, :last_name
|
250
|
+
property :age, with: -> (v) { v.to_i }
|
251
|
+
property :created_at, with: -> (v) { DateTime.parse(v) }
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
it 'returns json' do
|
256
|
+
expect(subject.as_json).to eq(
|
257
|
+
first_child_source.merge(
|
258
|
+
age: first_child_source[:age].to_i,
|
259
|
+
created_at: DateTime.parse(first_child_source[:created_at])
|
260
|
+
)
|
261
|
+
)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'awesome_print'
|
3
|
+
Bundler.setup
|
4
|
+
|
5
|
+
require 'coveralls'
|
6
|
+
Coveralls.wear!
|
7
|
+
|
8
|
+
require 'light_params'
|
9
|
+
Dir['./spec/support/**/*.rb'].sort.each { |f| require f }
|
10
|
+
|
11
|
+
RSpec.configure do |config|
|
12
|
+
config.filter_run :focus
|
13
|
+
config.run_all_when_everything_filtered = true
|
14
|
+
|
15
|
+
config.default_formatter = 'doc' if config.files_to_run.one?
|
16
|
+
|
17
|
+
config.profile_examples = 10
|
18
|
+
config.order = :random
|
19
|
+
|
20
|
+
Kernel.srand config.seed
|
21
|
+
|
22
|
+
config.expect_with :rspec do |expectations|
|
23
|
+
expectations.syntax = :expect
|
24
|
+
end
|
25
|
+
|
26
|
+
config.mock_with :rspec do |mocks|
|
27
|
+
mocks.syntax = :expect
|
28
|
+
mocks.verify_partial_doubles = true
|
29
|
+
end
|
30
|
+
end
|
31
|
+
require 'guard/rubocop'
|
@@ -0,0 +1,11 @@
|
|
1
|
+
def class_factory(opts = {}, &block)
|
2
|
+
Class.new(described_class).tap do |klass|
|
3
|
+
klass.class_eval(&block) if block_given?
|
4
|
+
Object.const_set(opts[:real_class_name], klass) if opts[:real_class_name]
|
5
|
+
klass.class_eval("def self.name; \"#{name}\"; end") if opts[:name]
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def object_factory(opts = {}, &block)
|
10
|
+
class_factory(opts, &block).new(opts.fetch(:params, {}))
|
11
|
+
end
|
metadata
ADDED
@@ -0,0 +1,220 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: light_params
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Pawel Niemczyk
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-02-17 00:00:00.000000000 Z
|
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'
|
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'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activemodel
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: ruby_dep
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.1'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.1'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.7'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.7'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '10.4'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '10.4'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: guard
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '2.12'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '2.12'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: guard-rspec
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '4.5'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '4.5'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: guard-rubocop
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '1.2'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '1.2'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: coveralls
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0.7'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0.7'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: awesome_print
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - "~>"
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '1.6'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - "~>"
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '1.6'
|
167
|
+
description: Light params
|
168
|
+
email:
|
169
|
+
- pniemczyk.info@gmail.com
|
170
|
+
executables: []
|
171
|
+
extensions: []
|
172
|
+
extra_rdoc_files: []
|
173
|
+
files:
|
174
|
+
- ".gitignore"
|
175
|
+
- ".rspec"
|
176
|
+
- ".rubocop.yml"
|
177
|
+
- ".travis.yml"
|
178
|
+
- Gemfile
|
179
|
+
- Guardfile
|
180
|
+
- LICENSE.txt
|
181
|
+
- README.md
|
182
|
+
- Rakefile
|
183
|
+
- lib/light_params.rb
|
184
|
+
- lib/light_params/errors.rb
|
185
|
+
- lib/light_params/lash.rb
|
186
|
+
- lib/light_params/lash_builder.rb
|
187
|
+
- lib/light_params/properties_configuration.rb
|
188
|
+
- lib/light_params/version.rb
|
189
|
+
- light_params.gemspec
|
190
|
+
- spec/lib/lash_spec.rb
|
191
|
+
- spec/spec_helper.rb
|
192
|
+
- spec/support/factory_helper.rb
|
193
|
+
homepage: https://github.com/pniemczyk/light_params
|
194
|
+
licenses:
|
195
|
+
- MIT
|
196
|
+
metadata: {}
|
197
|
+
post_install_message:
|
198
|
+
rdoc_options: []
|
199
|
+
require_paths:
|
200
|
+
- lib
|
201
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
202
|
+
requirements:
|
203
|
+
- - ">="
|
204
|
+
- !ruby/object:Gem::Version
|
205
|
+
version: '0'
|
206
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
207
|
+
requirements:
|
208
|
+
- - ">="
|
209
|
+
- !ruby/object:Gem::Version
|
210
|
+
version: '0'
|
211
|
+
requirements: []
|
212
|
+
rubyforge_project:
|
213
|
+
rubygems_version: 2.4.8
|
214
|
+
signing_key:
|
215
|
+
specification_version: 4
|
216
|
+
summary: Light params
|
217
|
+
test_files:
|
218
|
+
- spec/lib/lash_spec.rb
|
219
|
+
- spec/spec_helper.rb
|
220
|
+
- spec/support/factory_helper.rb
|