light_params 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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
@@ -0,0 +1,4 @@
1
+ --color
2
+ --require spec_helper
3
+ --format progress
4
+ --no-profile
@@ -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'
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ script: bundle exec rake
3
+ rvm:
4
+ - 2.2.5
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in light_params.gemspec
4
+ gemspec
@@ -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
@@ -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.
@@ -0,0 +1,119 @@
1
+ # LightParams
2
+
3
+ https://travis-ci.org/pniemczyk/light_params
4
+
5
+ [![Gem Version](https://badge.fury.io/rb/light_params.svg)](http://badge.fury.io/rb/light_params)
6
+ [![Build Status](https://travis-ci.org/pniemczyk/light_params.svg?branch=master)](https://travis-ci.org/pniemczyk/light_params)
7
+ [![Coverage Status](https://coveralls.io/repos/pniemczyk/light_params/badge.png)](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
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -0,0 +1,8 @@
1
+ require 'light_params/version'
2
+ require 'light_params/lash_builder'
3
+ require 'light_params/properties_configuration'
4
+ require 'light_params/errors'
5
+ require 'light_params/lash'
6
+
7
+ module LightParams
8
+ end
@@ -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,3 @@
1
+ module LightParams
2
+ VERSION = '1.0.0'
3
+ 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
@@ -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