arstotzka 1.4.0 → 1.4.1

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
  SHA256:
3
- metadata.gz: 3343d391090a1c5e806d56c9eb97790a79a04fbc24b707384a71024c3f894879
4
- data.tar.gz: da14356086e54f211d32a0725de04bd8ba01a2bb7c767ced8e17519f47f6fb37
3
+ metadata.gz: 2f85777523a289161b592aa87351fa89b9e255ff4af446b365699aa23f208f72
4
+ data.tar.gz: c9a7e10955ec91d3a1c356c1a0da69082e36f1c5b89abb76964cbdd92ba7a28f
5
5
  SHA512:
6
- metadata.gz: 4dabdf1acd44e98e8884a0106d84bd6e1f6e3cd33940b0a777049f66d58529757223dbf28e50ff6717764fe025905bf3d3b5d5a38ee710357fc891b3e6c6de61
7
- data.tar.gz: ed2fcefdd16da6ac23e8439a84f8158ad271da23385e6560f97197eafc1ba15b6d3a6150be56493767a4f06a19b82b6790386343a409f9b51d76afb3987fc966
6
+ metadata.gz: ae4b737d7c698ec03482a30b7ca5a715c413aa08bccd4863f2cdf081dc984f242171028deaa5256156b6b6b62555a23239327ba808523d5df1f0f756d57c5c5d
7
+ data.tar.gz: bd2e82f32e3cbdbc09178d8ae9224a9432b90c2d0ec2edef2148c99279a8617dc688f969d2b47d0510f2ff42c4b605cd5ab2c5e562fa54feee8cbc9c6a24a008
data/README.md CHANGED
@@ -19,7 +19,7 @@ JSON keys)
19
19
 
20
20
  Yard Documentation
21
21
  -------------------
22
- https://www.rubydoc.info/gems/arstotzka/1.4.0
22
+ https://www.rubydoc.info/gems/arstotzka/1.4.1
23
23
 
24
24
  Instalation
25
25
  ---------------
data/arstotzka.gemspec CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |gem|
20
20
  gem.require_paths = ['lib']
21
21
 
22
22
  gem.add_runtime_dependency 'activesupport', '~> 5.x'
23
- gem.add_runtime_dependency 'sinclair', '>= 1.4.0'
23
+ gem.add_runtime_dependency 'sinclair', '>= 1.4.1'
24
24
 
25
25
  gem.add_development_dependency 'bundler', '~> 1.16.1'
26
26
  gem.add_development_dependency 'pry-nav', '~> 0.2.4'
data/config/yardstick.yml CHANGED
@@ -27,6 +27,8 @@ rules:
27
27
  - Arstotzka::Fetcher::Cache#block
28
28
  - Arstotzka::Fetcher::Cache#options
29
29
  - Arstotzka::FetcherBuilder#options
30
+ - Arstotzka::KeyChanger#base_key
31
+ - Arstotzka::KeyChanger#options
30
32
  - Arstotzka::KeyReader#base_key
31
33
  - Arstotzka::KeyReader#hash
32
34
  - Arstotzka::KeyReader#options
@@ -35,6 +37,7 @@ rules:
35
37
  - Arstotzka::MethodBuilder#options
36
38
  - Arstotzka::Reader#keys
37
39
  - Arstotzka::Reader#options
40
+ - Arstotzka::PostProcessor#options
38
41
  - Arstotzka::Wrapper#options
39
42
  Summary::Presence:
40
43
  enabled: true
@@ -48,6 +51,9 @@ rules:
48
51
  - Arstotzka::Fetcher::Cache#options
49
52
  - Arstotzka::Fetcher::Cache#initialize
50
53
  - Arstotzka::FetcherBuilder#options
54
+ - Arstotzka::KeyChanger#initialize
55
+ - Arstotzka::KeyChanger#base_key
56
+ - Arstotzka::KeyChanger#options
51
57
  - Arstotzka::KeyReader#base_key
52
58
  - Arstotzka::KeyReader#hash
53
59
  - Arstotzka::KeyReader#options
@@ -56,6 +62,8 @@ rules:
56
62
  - Arstotzka::MethodBuilder#options
57
63
  - Arstotzka::Reader#keys
58
64
  - Arstotzka::Reader#options
65
+ - Arstotzka::PostProcessor#initialize
66
+ - Arstotzka::PostProcessor#options
59
67
  - Arstotzka::Wrapper#options
60
68
  Summary::Length:
61
69
  enabled: true
@@ -69,6 +69,64 @@ module Arstotzka
69
69
  #
70
70
  # Expose a field from the json/hash as a method
71
71
  #
72
+ # @param attr_names [Array<String,Symbol>] attributes being exposed
73
+ # @param options_hash [Hash] exposing options
74
+ #
75
+ # @option options_hash after [String,Symbol] instance method to be called on the
76
+ # returning value returned by {Crawler} before being returned by {Fetcher}.
77
+ # The result of the method call will be the actual value
78
+ # (used by {PostProcessor})
79
+ #
80
+ # @option options_hash after_each [String,Symbol] instance method to be
81
+ # called on each element found when crawling the hash.
82
+ # If an array should be returned, after_each will be called on each individual
83
+ # elements (even nil elements) while +after+ is only called on the
84
+ # collection. (used by {Wrapper})
85
+ #
86
+ # @option options_hash cached [Boolean,Symbol] Flag to ensure
87
+ # there value is cached after first fetching.
88
+ # (used by {Fetcher::Cache})
89
+ # - +false+/+nil+ : no cache, fetcher will always look in the hash
90
+ # for the value
91
+ # - +true+ : Simple cache, nil values are always considered
92
+ # not cached
93
+ # - +:full+ : cache even nil values
94
+ #
95
+ # @option options_hash case [Symbol] case type of the keys in the hash
96
+ # (used by {KeyChanger})
97
+ # - +:snake+ : snake_cased keys
98
+ # - +:lower_camel+ : lowerCamelCased keys
99
+ # - +:upper_camel+ : UperCamelCased keys
100
+ #
101
+ # @option options_hash compact [Boolean] flag signallying if nil values should be
102
+ # removed of array (applying +Array#compact+) (used by {Crawler})
103
+ #
104
+ # @option options_hash default [Object] default value to be returned when failing
105
+ # to fetch a value (used by {Crawler})
106
+ #
107
+ # @option options_hash flatten [Boolean] flag signallying if multi levels
108
+ # arrays should be flattened to one level array (applying +Array#flatten+)
109
+ # (used by {PostProcessor})
110
+ #
111
+ # @option options_hash full_path [String] full path of keys to be used in when
112
+ # not wanting to have the attribute defined as key. (eg. +'person.name'+)
113
+ # (used by {Crawler})
114
+ #
115
+ # @option options_hash klass [Class] class to wrap the value (used by {Wrapper})
116
+ #
117
+ # @option options_hash json [String,Symbol] name of the method or variable
118
+ # used to fetch the hash to be crawled (eg. +:hash+, +:@hash+, +"@@config"+)
119
+ # (used by {HashReader})
120
+ #
121
+ # @option options_hash path [String,Symbol] base path to be crawled.
122
+ # (used by {Crawler})
123
+ #
124
+ # @option options_hash type [String,Symbol] type to cast the value. The
125
+ # possible type_cast is defined by {TypeCast} (used by {Wrapper})
126
+ # - +integer+
127
+ # - +string+
128
+ # - +float+
129
+ #
72
130
  # @example
73
131
  # class MyModel
74
132
  # include Arstotzka
@@ -95,6 +153,7 @@ module Arstotzka
95
153
  #
96
154
  # @return [Array<Sinclair::MethodDefinition>]
97
155
  #
156
+ # @see Config
98
157
  # @see MethodBuilder Arstotzka::MethodBuilder
99
158
  # @see
100
159
  # https://www.rubydoc.info/gems/activesupport/5.2.2/ActiveSupport/Concern
@@ -5,12 +5,48 @@ module Arstotzka
5
5
  #
6
6
  # Arstotzka configuration
7
7
  #
8
- # Configuration is
8
+ # Configuration of Arstotzka is done through
9
+ # +Arstotzka.configure+ which configures using
10
+ # {Arstotzka::Config} by +Sinclar::Configurable+
9
11
  #
10
- # @see https://www.rubydoc.info/gems/sinclair/1.4.0/Sinclair/Config Sinclair::Config
12
+ # @see https://www.rubydoc.info/gems/sinclair/1.4.1/Sinclair/Config
13
+ # Sinclair::Config
14
+ #
15
+ # @example Redefining json method and case type
16
+ # class Office
17
+ # include Arstotzka
18
+ #
19
+ # expose :employes, full_path: 'employes.first_name',
20
+ # compact: true
21
+ #
22
+ # def initialize(hash)
23
+ # @hash = hash
24
+ # end
25
+ # end
26
+ #
27
+ # hash = {
28
+ # employes: [{
29
+ # first_name: 'Rob'
30
+ # }, {
31
+ # first_name: 'Klara'
32
+ # }]
33
+ # }
34
+ #
35
+ # office = Office.new(hash)
36
+ #
37
+ # office.employes # raises NoMethodError as json is not a method
38
+ #
39
+ # Arstotzka.configure { json :@hash }
40
+ #
41
+ # office.employes # returns []
42
+ #
43
+ # Arstotzka.configure { |c| c.case :snake }
44
+ #
45
+ # office.employes # returns %w[Rob Klara]
11
46
  #
12
47
  # @example (see #options)
13
48
  class Config < Sinclair::Config
49
+ # Default values for {ClassMethods#expose}
14
50
  DEFAULT_CONFIGS = {
15
51
  after: false,
16
52
  after_each: nil,
@@ -96,8 +96,7 @@ module Arstotzka
96
96
  # @return [TrueClass,FalseClass]
97
97
  def ==(other)
98
98
  return false unless other.class == self.class
99
- options == other.options &&
100
- instance == other.instance
99
+ options == other.options
101
100
  end
102
101
 
103
102
  protected
@@ -107,7 +106,6 @@ module Arstotzka
107
106
  private
108
107
 
109
108
  # @private
110
- delegate :instance, :after, :flatten, to: :options
111
109
  delegate :wrap, to: :wrapper
112
110
  delegate :hash, to: :hash_reader
113
111
 
@@ -120,9 +118,16 @@ module Arstotzka
120
118
  #
121
119
  # @return [Object]
122
120
  def fetch_value
123
- value = crawler.value(hash)
124
- value.flatten! if flatten && value.is_a?(Array)
125
- after ? instance.send(after, value) : value
121
+ post_processor.process crawler.value(hash)
122
+ end
123
+
124
+ # @private
125
+ #
126
+ # post processor for wrapping and filtering collection before return
127
+ #
128
+ # @return [PostProcessor]
129
+ def post_processor
130
+ @post_processor ||= PostProcessor.new(options)
126
131
  end
127
132
 
128
133
  # @private
@@ -134,10 +139,9 @@ module Arstotzka
134
139
  #
135
140
  # @return [Arstotzka::Crawler] the crawler object
136
141
  def crawler
137
- @crawler ||=
138
- Crawler.new(options) do |value|
139
- wrap(value)
140
- end
142
+ @crawler ||= Crawler.new(options) do |value|
143
+ wrap(value)
144
+ end
141
145
  end
142
146
 
143
147
  # @private
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Arstotzka
4
+ # @api private
5
+ #
6
+ # Class responsible for changing a key
7
+ class KeyChanger
8
+ include Base
9
+
10
+ # @param [String] base_key The key to be checked
11
+ # (before case change)
12
+ #
13
+ # @overload initialize(base_key, options_hash)
14
+ # @param options_hash [Hash] options passed on expose
15
+ # @option options_hash case [Symbol] case type for key
16
+ # transformation
17
+ # - +:snake+ : snake_cased keys
18
+ # - +:lower_camel+ : lowerCamelCased keys
19
+ # - +:upper_camel+ : UperCamelCased keys
20
+ # @overload initialize(base_key, options)
21
+ # @param options [Option] options passed on expose
22
+ #
23
+ # @example
24
+ # changer = Arstotzka::KeyChanger.new('the_key', case: :upper_camel)
25
+ # changer.key # returns 'TheKey'
26
+ def initialize(base_key, options_hash = {})
27
+ self.options = options_hash
28
+ @base_key = base_key
29
+ end
30
+
31
+ # Transforms the key to have the correct case
32
+ #
33
+ # the possible cases (instance attribute) are
34
+ # - lower_camel: for cammel case with first letter lowercase
35
+ # - upper_camel: for cammel case with first letter uppercase
36
+ # - snake: for snake case
37
+ #
38
+ # @return [String] the string transformed
39
+ def key
40
+ @key ||= case options.case
41
+ when :lower_camel
42
+ base_key.camelize(:lower)
43
+ when :upper_camel
44
+ base_key.camelize(:upper)
45
+ when :snake
46
+ base_key.underscore
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ attr_reader :base_key, :options
53
+ end
54
+ end
@@ -48,6 +48,7 @@ module Arstotzka
48
48
  private
49
49
 
50
50
  attr_reader :hash, :base_key, :options
51
+ delegate :key, to: :key_changer
51
52
 
52
53
  # @private
53
54
  #
@@ -66,23 +67,11 @@ module Arstotzka
66
67
 
67
68
  # @private
68
69
  #
69
- # Transforms the key to have the correct case
70
+ # Returns key changer for getting the correct key
70
71
  #
71
- # the possible cases (instance attribute) are
72
- # - lower_camel: for cammel case with first letter lowercase
73
- # - upper_camel: for cammel case with first letter uppercase
74
- # - snake: for snake case
75
- #
76
- # @return [String] the string transformed
77
- def key
78
- @key ||= case options.case
79
- when :lower_camel
80
- base_key.camelize(:lower)
81
- when :upper_camel
82
- base_key.camelize(:upper)
83
- when :snake
84
- base_key.underscore
85
- end
72
+ # @return [KeyChanger]
73
+ def key_changer
74
+ @key_changer ||= KeyChanger.new(base_key, options)
86
75
  end
87
76
  end
88
77
  end
@@ -246,47 +246,26 @@ module Arstotzka
246
246
  class Options < ::OpenStruct
247
247
  # Creates a new instance of Options
248
248
  #
249
- # @param options [Hash] options hash
249
+ # @param options_hash [Hash] options hash
250
250
  # Options hash are initialized when using {ClassMethods#expose}
251
251
  #
252
- # @option options [String,Symbol] after: {Fetcher} option with the name of the method to be
253
- # called once the value is fetched for mapping the value
252
+ # @option (see ClassMethods#expose)
254
253
  #
255
- # @option options [String,Symbol] after_each: {Wrapper} option with method that will be called
256
- # on each individual result (while after is called on the whole collection)
257
- # @option options [Boolean] cached: flag if the result should be memorized instead of repeating
258
- # the crawling
259
- # @option options [String,Symbol] case: {Reader} flag definining on which case will
260
- # the keys be defined
261
- # - lower_camel: keys in the hash are lowerCamelCase
262
- # - upper_camel: keys in the hash are UpperCamelCase
263
- # - snake: keys in the hash are snake_case
264
- # @option options [Boolean] compact: {Crawler} flag to apply Array#compact thus
265
- # removing nil results
266
- # @option options [Boolean] default: {Crawler} option to return default value instead of nil
267
- # @option options [Boolean] flatten: {Fetcher} flag to aplly Array#flatten thus
268
- # avoing nested arrays
269
- # @option options [String,Symbol] full_path: path of hash attributes to find exacttly where the
270
- # value live (ignoring the attribute name)
271
- # @option options [Class] klass: {Fetcher} option that, when passed, wraps the individual
272
- # results in an instance of the given class
273
- # @option options [String,Symbol] json: name of the method containing the hash to be crawled
274
- # @option options [String,Symbol] path path of hash attributes to find the root
275
- # where the attribute live (then fetching it using the attribute name)
276
- # @option options [String,Symbol] type: {Fetcher} option declaring the type of the returned
277
- # value (to use casting) (see {TypeCast})
278
- # - integer
279
- # - string
280
- # - float
254
+ # @option options_hash instance [Object] instance whose method
255
+ # was called
256
+ #
257
+ # @option options_hash key [Symbol,String] name of method called.
258
+ # This will be used as instance variable when caching results
281
259
  #
282
- # @see Arstotzka::Options::DEFAULT_OPTIONS
283
260
  # @return [Arstotzka::Options]
284
- def initialize(options)
285
- klass = options.delete(:class)
261
+ #
262
+ # @see Config
263
+ def initialize(options_hash)
264
+ klass = options_hash.delete(:class)
286
265
  warn ":class has been deprecated, prefer 'expose klass: #{klass}'" if klass
287
- options[:klass] ||= klass
266
+ options_hash[:klass] ||= klass
288
267
 
289
- super(options)
268
+ super(options_hash)
290
269
  end
291
270
 
292
271
  # @private
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Arstotzka
4
+ # @api private
5
+ #
6
+ # Class reponsible for processing the result of {Crawler#crawl}.
7
+ #
8
+ # PostProcessor proccess the whole collection and not
9
+ # individual results
10
+ #
11
+ # @example Simple Usage
12
+ # class Employe
13
+ # attr_reader :name, :age, :company
14
+ #
15
+ # def initialize(name:, age:, company:)
16
+ # @name = name
17
+ # @age = age
18
+ # @company = company
19
+ # end
20
+ #
21
+ # def adult?
22
+ # age >= 18
23
+ # end
24
+ #
25
+ # def ==(other)
26
+ # return unless other.class == self.class
27
+ # other.name == name &&
28
+ # other.age == age &&
29
+ # other.company == company
30
+ # end
31
+ # end
32
+ #
33
+ # class Company
34
+ # def create_employes(people)
35
+ # people.map do |person|
36
+ # Employe.new(company: self, **person)
37
+ # end.select(&:adult?)
38
+ # end
39
+ # end
40
+ #
41
+ # company = Company.new
42
+ #
43
+ # options = {
44
+ # after: :create_employes,
45
+ # flatten: true,
46
+ # instance: company
47
+ # }
48
+ #
49
+ # processor = Arstotzka::PostProcessor.new(options)
50
+ #
51
+ # value = [
52
+ # [
53
+ # { name: 'Bob', age: 21 },
54
+ # { name: 'Rose', age: 19 }
55
+ # ], [
56
+ # { name: 'Klara', age: 18 },
57
+ # { name: 'Al', age: 15 }
58
+ # ]
59
+ # ]
60
+ #
61
+ # processor.process(value)
62
+ #
63
+ # # returns [
64
+ # # Employe.new(name: 'Bob', age: 21, company: company),
65
+ # # Employe.new(name: 'Rose', age: 19, company: company),
66
+ # # Employe.new(name: 'Klara', age: 18, company: company)
67
+ # # ]
68
+ class PostProcessor
69
+ include Base
70
+
71
+ # @overload initialize(options_hash)
72
+ # @param options_hash [Hash] options passed by
73
+ # {ClassMethods#expose}
74
+ # @option options_hash instance [Objct]
75
+ # @option options_hash after [String,Symbol] instance method to be called on the
76
+ # returning value returned by {Crawler} before being returned by {Fetcher}.
77
+ # @option options_hash flatten [Boolean] flag signallying if multi levels
78
+ # arrays should be flattened to one level array (applying +Array#flatten+)
79
+ # @overload initialize(options)
80
+ # @param options [Hash] options passed by {ClassMethods#expose}
81
+ def initialize(options_hash = {})
82
+ self.options = options_hash
83
+ end
84
+
85
+ # Apply transformation and filters on the result
86
+ #
87
+ # @param value [Object] value is returned from crawler
88
+ # being a single object, or an array.
89
+ #
90
+ # @return [Object]
91
+ def process(value)
92
+ value.flatten! if flatten && value.is_a?(Array)
93
+
94
+ return value unless after
95
+
96
+ instance.send(after, value)
97
+ end
98
+
99
+ private
100
+
101
+ attr_reader :options
102
+
103
+ delegate :instance, :after, :flatten, to: :options
104
+ end
105
+ end
@@ -22,8 +22,6 @@ module Arstotzka
22
22
  # @return [Arstotzka::Reader]
23
23
  def initialize(options_hash = {})
24
24
  self.options = options_hash
25
-
26
- @keys = options.keys
27
25
  end
28
26
 
29
27
  # Reads the value of one key in the hash
@@ -81,6 +79,7 @@ module Arstotzka
81
79
  private
82
80
 
83
81
  # @private
84
- attr_reader :keys, :options
82
+ attr_reader :options
83
+ delegate :keys, to: :options
85
84
  end
86
85
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Arstotzka
4
- VERSION = '1.4.0'
4
+ VERSION = '1.4.1'
5
5
  end
data/lib/arstotzka.rb CHANGED
@@ -175,10 +175,12 @@ module Arstotzka
175
175
  autoload :Exception, 'arstotzka/exception'
176
176
  autoload :Fetcher, 'arstotzka/fetcher'
177
177
  autoload :FetcherBuilder, 'arstotzka/fetcher_builder'
178
+ autoload :KeyChanger, 'arstotzka/key_changer'
178
179
  autoload :KeyReader, 'arstotzka/key_reader'
179
180
  autoload :HashReader, 'arstotzka/hash_reader'
180
181
  autoload :MethodBuilder, 'arstotzka/method_builder'
181
182
  autoload :Options, 'arstotzka/options'
183
+ autoload :PostProcessor, 'arstotzka/post_processor'
182
184
  autoload :Reader, 'arstotzka/reader'
183
185
  autoload :TypeCast, 'arstotzka/type_cast'
184
186
  autoload :Wrapper, 'arstotzka/wrapper'
@@ -6,6 +6,41 @@ describe Arstotzka::Config do
6
6
  describe 'yard' do
7
7
  subject(:config) { Arstotzka.config }
8
8
 
9
+ after { Arstotzka.reset_config }
10
+
11
+ describe 'Redefining json method and case type' do
12
+ let(:office) { Office.new(hash) }
13
+
14
+ let(:hash) do
15
+ {
16
+ employes: [{
17
+ first_name: 'Rob'
18
+ }, {
19
+ first_name: 'Klara'
20
+ }]
21
+ }
22
+ end
23
+
24
+ let(:error_message) do
25
+ "undefined method `json' for #{office}\nDid you mean? JSON"
26
+ end
27
+
28
+ it do
29
+ expect { office.employes }
30
+ .to raise_error(NoMethodError, error_message)
31
+ end
32
+
33
+ context 'when json option is defined' do
34
+ before { Arstotzka.configure { json :@hash } }
35
+
36
+ it do
37
+ expect { Arstotzka.configure { |c| c.case :snake } }
38
+ .to change(office, :employes)
39
+ .from([]).to(%w[Rob Klara])
40
+ end
41
+ end
42
+ end
43
+
9
44
  describe '#options' do
10
45
  let(:overrides) { { klass: Person } }
11
46
 
@@ -30,8 +65,6 @@ describe Arstotzka::Config do
30
65
  end
31
66
  end
32
67
 
33
- after { Arstotzka.reset_config }
34
-
35
68
  it 'configure options to use snake case' do
36
69
  expect(config.options(overrides).to_h).to eq(expected)
37
70
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Arstotzka::KeyChanger do
6
+ describe '#yard' do
7
+ subject(:key_changer) do
8
+ described_class.new('the_key', case: :upper_camel)
9
+ end
10
+
11
+ it 'converts key case' do
12
+ expect(key_changer.key).to eq('TheKey')
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Arstotzka::PostProcessor do
6
+ describe 'yard' do
7
+ subject(:processor) { described_class.new(options) }
8
+
9
+ let(:company) { Company.new }
10
+
11
+ let(:options) do
12
+ {
13
+ after: :create_employes,
14
+ flatten: true,
15
+ instance: company
16
+ }
17
+ end
18
+
19
+ let(:value) do
20
+ [
21
+ [
22
+ { name: 'Bob', age: 21 },
23
+ { name: 'Rose', age: 19 }
24
+ ], [
25
+ { name: 'Klara', age: 18 },
26
+ { name: 'Al', age: 15 }
27
+ ]
28
+ ]
29
+ end
30
+
31
+ let(:expected) do
32
+ [
33
+ Employe.new(name: 'Bob', age: 21, company: company),
34
+ Employe.new(name: 'Rose', age: 19, company: company),
35
+ Employe.new(name: 'Klara', age: 18, company: company)
36
+ ]
37
+ end
38
+
39
+ describe 'Simple usage' do
40
+ it 'maps and filter' do
41
+ expect(processor.process(value)).to eq(expected)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Arstotzka::KeyChanger do
6
+ subject(:key_changer) { described_class.new(base_key, options) }
7
+
8
+ describe '#key' do
9
+ let(:base_key) { 'the_key' }
10
+
11
+ context 'when no options are given' do
12
+ let(:options) { {} }
13
+
14
+ it 'returns lower camelized key' do
15
+ expect(key_changer.key).to eq('theKey')
16
+ end
17
+ end
18
+
19
+ context 'when setting upper camel' do
20
+ let(:options) { { case: :upper_camel } }
21
+
22
+ it 'returns upper camelized key' do
23
+ expect(key_changer.key).to eq('TheKey')
24
+ end
25
+ end
26
+
27
+ context 'when setting snake' do
28
+ let(:options) { { case: :snake } }
29
+ let(:base_key) { 'TheKey' }
30
+
31
+ it 'returns lower snakecased key' do
32
+ expect(key_changer.key).to eq('the_key')
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Arstotzka::PostProcessor do
6
+ subject(:processor) { described_class.new(options) }
7
+
8
+ let(:options) { {} }
9
+ let(:value) { [%w[Bob Klara], %w[Rose Aria]] }
10
+
11
+ describe '#process' do
12
+ context 'when no options are given' do
13
+ it 'returns the value with no change' do
14
+ expect(processor.process(value)).to eq(value)
15
+ end
16
+ end
17
+
18
+ context 'when passing flatten option' do
19
+ let(:options) { { flatten: true } }
20
+
21
+ it 'flattens the array' do
22
+ expect(processor.process(value))
23
+ .to eq(%w[Bob Klara Rose Aria])
24
+ end
25
+ end
26
+
27
+ context 'when passing after' do
28
+ let(:company) { Company.new }
29
+
30
+ let(:options) do
31
+ { after: :create_employes, instance: company }
32
+ end
33
+
34
+ let(:value) do
35
+ [
36
+ { name: 'Bob', age: 21 },
37
+ { name: 'Klara', age: 18 },
38
+ { name: 'Rose', age: 16 },
39
+ { name: 'Al', age: 15 }
40
+ ]
41
+ end
42
+
43
+ let(:expected) do
44
+ [
45
+ Employe.new(name: 'Bob', age: 21, company: company),
46
+ Employe.new(name: 'Klara', age: 18, company: company)
47
+ ]
48
+ end
49
+
50
+ it 'maps and filtes by method' do
51
+ expect(processor.process(value)).to eq(expected)
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Company
4
+ def create_employes(people)
5
+ people.map do |person|
6
+ Employe.new(company: self, **person)
7
+ end.select(&:adult?)
8
+ end
9
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Employe
4
+ attr_reader :name, :age, :company
5
+
6
+ def initialize(name:, age:, company:)
7
+ @name = name
8
+ @age = age
9
+ @company = company
10
+ end
11
+
12
+ def adult?
13
+ age >= 18
14
+ end
15
+
16
+ def ==(other)
17
+ return unless other.class == self.class
18
+ other.name == name &&
19
+ other.age == age &&
20
+ other.company == company
21
+ end
22
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Office
4
+ include Arstotzka
5
+
6
+ expose :employes, full_path: 'employes.first_name',
7
+ compact: true
8
+
9
+ def initialize(hash)
10
+ @hash = hash
11
+ end
12
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: arstotzka
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Darthjee
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-07-09 00:00:00.000000000 Z
11
+ date: 2019-07-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 1.4.0
33
+ version: 1.4.1
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 1.4.0
40
+ version: 1.4.1
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -227,9 +227,11 @@ files:
227
227
  - lib/arstotzka/fetcher/cache.rb
228
228
  - lib/arstotzka/fetcher_builder.rb
229
229
  - lib/arstotzka/hash_reader.rb
230
+ - lib/arstotzka/key_changer.rb
230
231
  - lib/arstotzka/key_reader.rb
231
232
  - lib/arstotzka/method_builder.rb
232
233
  - lib/arstotzka/options.rb
234
+ - lib/arstotzka/post_processor.rb
233
235
  - lib/arstotzka/reader.rb
234
236
  - lib/arstotzka/type_cast.rb
235
237
  - lib/arstotzka/version.rb
@@ -251,9 +253,11 @@ files:
251
253
  - spec/integration/yard/arstotzka/fetcher_builder_spec.rb
252
254
  - spec/integration/yard/arstotzka/fetcher_spec.rb
253
255
  - spec/integration/yard/arstotzka/hash_reader_spec.rb
256
+ - spec/integration/yard/arstotzka/key_changer_spec.rb
254
257
  - spec/integration/yard/arstotzka/key_reader_spec.rb
255
258
  - spec/integration/yard/arstotzka/method_builder_spec.rb
256
259
  - spec/integration/yard/arstotzka/options_spec.rb
260
+ - spec/integration/yard/arstotzka/post_processor_spec.rb
257
261
  - spec/integration/yard/arstotzka/reader_spec.rb
258
262
  - spec/integration/yard/arstotzka/type_cast_spec.rb
259
263
  - spec/integration/yard/arstotzka/wrapper_spec.rb
@@ -264,9 +268,11 @@ files:
264
268
  - spec/lib/arstotzka/fetcher_builder_spec.rb
265
269
  - spec/lib/arstotzka/fetcher_spec.rb
266
270
  - spec/lib/arstotzka/hash_reader_spec.rb
271
+ - spec/lib/arstotzka/key_changer_spec.rb
267
272
  - spec/lib/arstotzka/key_reader_spec.rb
268
273
  - spec/lib/arstotzka/method_builder_spec.rb
269
274
  - spec/lib/arstotzka/options_spec.rb
275
+ - spec/lib/arstotzka/post_processor_spec.rb
270
276
  - spec/lib/arstotzka/reader_spec.rb
271
277
  - spec/lib/arstotzka/wrapper_spec.rb
272
278
  - spec/lib/arstotzka_spec.rb
@@ -287,14 +293,17 @@ files:
287
293
  - spec/support/models/car_collector.rb
288
294
  - spec/support/models/collector.rb
289
295
  - spec/support/models/collector/game.rb
296
+ - spec/support/models/company.rb
290
297
  - spec/support/models/customer.rb
291
298
  - spec/support/models/drink.rb
299
+ - spec/support/models/employe.rb
292
300
  - spec/support/models/game.rb
293
301
  - spec/support/models/group.rb
294
302
  - spec/support/models/house.rb
295
303
  - spec/support/models/job_seeker.rb
296
304
  - spec/support/models/my_model.rb
297
305
  - spec/support/models/my_parser.rb
306
+ - spec/support/models/office.rb
298
307
  - spec/support/models/person.rb
299
308
  - spec/support/models/request.rb
300
309
  - spec/support/models/restaurant.rb
@@ -344,9 +353,11 @@ test_files:
344
353
  - spec/integration/yard/arstotzka/fetcher_builder_spec.rb
345
354
  - spec/integration/yard/arstotzka/fetcher_spec.rb
346
355
  - spec/integration/yard/arstotzka/hash_reader_spec.rb
356
+ - spec/integration/yard/arstotzka/key_changer_spec.rb
347
357
  - spec/integration/yard/arstotzka/key_reader_spec.rb
348
358
  - spec/integration/yard/arstotzka/method_builder_spec.rb
349
359
  - spec/integration/yard/arstotzka/options_spec.rb
360
+ - spec/integration/yard/arstotzka/post_processor_spec.rb
350
361
  - spec/integration/yard/arstotzka/reader_spec.rb
351
362
  - spec/integration/yard/arstotzka/type_cast_spec.rb
352
363
  - spec/integration/yard/arstotzka/wrapper_spec.rb
@@ -357,9 +368,11 @@ test_files:
357
368
  - spec/lib/arstotzka/fetcher_builder_spec.rb
358
369
  - spec/lib/arstotzka/fetcher_spec.rb
359
370
  - spec/lib/arstotzka/hash_reader_spec.rb
371
+ - spec/lib/arstotzka/key_changer_spec.rb
360
372
  - spec/lib/arstotzka/key_reader_spec.rb
361
373
  - spec/lib/arstotzka/method_builder_spec.rb
362
374
  - spec/lib/arstotzka/options_spec.rb
375
+ - spec/lib/arstotzka/post_processor_spec.rb
363
376
  - spec/lib/arstotzka/reader_spec.rb
364
377
  - spec/lib/arstotzka/wrapper_spec.rb
365
378
  - spec/lib/arstotzka_spec.rb
@@ -380,14 +393,17 @@ test_files:
380
393
  - spec/support/models/car_collector.rb
381
394
  - spec/support/models/collector.rb
382
395
  - spec/support/models/collector/game.rb
396
+ - spec/support/models/company.rb
383
397
  - spec/support/models/customer.rb
384
398
  - spec/support/models/drink.rb
399
+ - spec/support/models/employe.rb
385
400
  - spec/support/models/game.rb
386
401
  - spec/support/models/group.rb
387
402
  - spec/support/models/house.rb
388
403
  - spec/support/models/job_seeker.rb
389
404
  - spec/support/models/my_model.rb
390
405
  - spec/support/models/my_parser.rb
406
+ - spec/support/models/office.rb
391
407
  - spec/support/models/person.rb
392
408
  - spec/support/models/request.rb
393
409
  - spec/support/models/restaurant.rb