arstotzka 1.3.2 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -17,7 +17,7 @@ module Arstotzka
17
17
  # end
18
18
  # end
19
19
  #
20
- # options = Arstotzka::Options.new(key: :id, path: :person)
20
+ # options = { key: :id, path: :person }
21
21
  # builder = Arstotzka::FetcherBuilder.new(options)
22
22
  # instance = MyModel.new(
23
23
  # person: {
@@ -29,17 +29,11 @@ module Arstotzka
29
29
  #
30
30
  # fetcher.fetch # returns 101
31
31
  class FetcherBuilder
32
- include Base
33
-
34
32
  # Creates an instance of Artotzka::FetcherBuilder
35
33
  #
36
- # @overload initialize(options_hash = {})
37
- # @param options_hash [Hash] options (see {Options})
38
- #
39
- # @overload initialize(options)
40
- # @param options [Arstotzka::Options] options
41
- def initialize(options_hash = {})
42
- self.options = options_hash
34
+ # @param options [Hash] options (see {Options})
35
+ def initialize(options = {})
36
+ @options = options
43
37
  end
44
38
 
45
39
  # Builds a fetcher responsible for fetchin a value
@@ -62,12 +56,12 @@ module Arstotzka
62
56
  # end
63
57
  # end
64
58
  #
65
- # options = Arstotzka::Options.new(
59
+ # options = {
66
60
  # key: :player_ids,
67
61
  # full_path: 'teams.players.person_id',
68
62
  # flatten: true,
69
63
  # case: :snake
70
- # )
64
+ # }
71
65
  # builder = Arstotzka::FetcherBuilder.new(options)
72
66
  # hash = {
73
67
  # teams: [
@@ -142,9 +136,9 @@ module Arstotzka
142
136
  #
143
137
  # instance = StarGazer.new(hash)
144
138
  #
145
- # options = Arstotzka::Options.new(
139
+ # options = {
146
140
  # key: :stars, klass: Star, after: :only_yellow
147
- # )
141
+ # }
148
142
  #
149
143
  # builder = Arstotzka::FetcherBuilder.new(options)
150
144
  # fetcher = builder.build(instance)
@@ -156,7 +150,11 @@ module Arstotzka
156
150
  #
157
151
  # @return Arstotzka::Fetcher
158
152
  def build(instance)
159
- Fetcher.new(options.merge(instance: instance))
153
+ fetcher_options = Arstotzka.config.options(
154
+ options.merge(instance: instance)
155
+ )
156
+
157
+ Fetcher.new(fetcher_options)
160
158
  end
161
159
 
162
160
  private
@@ -73,8 +73,6 @@ module Arstotzka
73
73
  # - upper_camel: for cammel case with first letter uppercase
74
74
  # - snake: for snake case
75
75
  #
76
- # @param [String] key the key to be transformed
77
- #
78
76
  # @return [String] the string transformed
79
77
  def key
80
78
  @key ||= case options.case
@@ -23,13 +23,13 @@ module Arstotzka
23
23
  # 'cars' => 2.0
24
24
  # )
25
25
  #
26
- # options = Arstotzka::Options.new(full_path: 'name.first')
26
+ # options = { full_path: 'name.first' }
27
27
  # builder = Arstotzka::MethodBuilder.new([ :first_name ], MyModel, options)
28
28
  # builder.build
29
29
  #
30
30
  # instance.first_name # returns 'John'
31
31
  #
32
- # options = Arstotzka::Options.new(type: :integer)
32
+ # options = { type: :integer }
33
33
  # builder = Arstotzka::MethodBuilder.new([ :age, 'cars' ], MyModel, options)
34
34
  # builder.build
35
35
  #
@@ -38,24 +38,18 @@ module Arstotzka
38
38
  #
39
39
  # @see https://www.rubydoc.info/gems/sinclair Sinclair
40
40
  class MethodBuilder < Sinclair
41
- include Base
42
41
  # Returns new instance of Arstotzka::MethodBuilder
43
42
  #
44
43
  # @param attr_names [Array<Symbol>] list of attributes to be fetched from the hash/json
45
44
  # @param klass [Class] class to receive the methods
46
45
  # (using {https://www.rubydoc.info/gems/sinclair Sinclair})
47
- #
48
- # @overload initialize(attr_names, klass, options_hash={})
49
- # @param options_hash [Hash] hash containing extra options
50
- #
51
- # @overload initialize(attr_names, klass, options)
52
- # @param options [Arstotzka::Options] options of initialization object
46
+ # @param options [Hash] hash containing extra options
53
47
  #
54
48
  # @see https://www.rubydoc.info/gems/sinclair Sinclair
55
49
  # @see Arstotzka::Options
56
50
  def initialize(attr_names, klass, options = {})
57
51
  super(klass)
58
- self.options = options
52
+ @options = options
59
53
 
60
54
  @attr_names = attr_names
61
55
  init
@@ -65,7 +59,7 @@ module Arstotzka
65
59
 
66
60
  # @private
67
61
  attr_reader :attr_names, :options
68
- delegate :path, :full_path, :cached, to: :options
62
+ delegate to: :options
69
63
 
70
64
  # @private
71
65
  #
@@ -89,23 +83,10 @@ module Arstotzka
89
83
  # @see Sinclair
90
84
  def add_attr(attribute)
91
85
  klass.add_fetcher(attribute, options)
92
- add_method attribute, attr_fetcher(attribute), cached: cached
93
- end
94
86
 
95
- # Returns the code needed to initialize fetcher
96
- #
97
- # @param [String,Symbol] attribute name of method / attribute
98
- #
99
- # @return [String] method code
100
- #
101
- # @see Sinclair
102
- # @see Artotzka::Fetcher
103
- def attr_fetcher(attribute)
104
- <<-CODE
105
- begin
106
- self.class.fetcher_for(:#{attribute}, self).fetch
107
- end
108
- CODE
87
+ add_method attribute do
88
+ self.class.fetcher_for(attribute, self).fetch
89
+ end
109
90
  end
110
91
  end
111
92
  end
@@ -5,8 +5,7 @@ module Arstotzka
5
5
  #
6
6
  # Class responsible to hold the options
7
7
  #
8
- # Options is initialized and merged with {DEFAULT_OPTIONS}
9
- # when using {ClassMethods#expose}
8
+ # Options is initialized when using {ClassMethods#expose}
10
9
  #
11
10
  # @example Using options klass and after
12
11
  # class Customer
@@ -245,27 +244,10 @@ module Arstotzka
245
244
  # # Linda Ariel
246
245
  # # ]
247
246
  class Options < ::OpenStruct
248
- DEFAULT_OPTIONS = {
249
- after: false,
250
- after_each: nil,
251
- cached: false,
252
- case: :lower_camel,
253
- compact: false,
254
- default: nil,
255
- flatten: false,
256
- full_path: nil,
257
- json: :json,
258
- klass: nil,
259
- path: nil,
260
- type: :none
261
- }.freeze
262
-
263
247
  # Creates a new instance of Options
264
248
  #
265
249
  # @param options [Hash] options hash
266
- #
267
- # Options hash are initialized and merged with {DEFAULT_OPTIONS}
268
- # when using {ClassMethods#expose}
250
+ # Options hash are initialized when using {ClassMethods#expose}
269
251
  #
270
252
  # @option options [String,Symbol] after: {Fetcher} option with the name of the method to be
271
253
  # called once the value is fetched for mapping the value
@@ -304,7 +286,7 @@ module Arstotzka
304
286
  warn ":class has been deprecated, prefer 'expose klass: #{klass}'" if klass
305
287
  options[:klass] ||= klass
306
288
 
307
- super(DEFAULT_OPTIONS.merge(options))
289
+ super(options)
308
290
  end
309
291
 
310
292
  # @private
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Arstotzka
4
- VERSION = '1.3.2'
4
+ VERSION = '1.4.0'
5
5
  end
@@ -4,7 +4,7 @@ DIFF_LIST=$(git diff --name-only $CIRCLE_SHA1 $(git merge-base $CIRCLE_SHA1 orig
4
4
 
5
5
  if [ ! -z "$DIFF_LIST" ]; then
6
6
  mkdir -p tmp/rubycritic/compare
7
- bundle exec rubycritic --format console --branch origin/master -t 0 $DIFF_LIST
7
+ bundle exec rubycritic --format console --branch origin/master -t 0 --maximum-decrease 1 $DIFF_LIST
8
8
  else
9
9
  echo "No changes detected. Skipping rubycritic..."
10
10
  fi
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Arstotzka::Config do
6
+ describe 'readme' do
7
+ subject(:restaurant) { Restaurant.new(hash) }
8
+
9
+ let(:hash) do
10
+ {
11
+ restaurant: {
12
+ complete_meals: {
13
+ dishes: %w[
14
+ Goulash
15
+ Spaghetti
16
+ Pizza
17
+ ]
18
+ }
19
+ }
20
+ }
21
+ end
22
+
23
+ after { Arstotzka.reset_config }
24
+
25
+ it 'does not find the values' do
26
+ expect { restaurant.dishes }.to raise_error(NoMethodError)
27
+ end
28
+
29
+ context 'when configuring json to be instance_variable' do
30
+ before do
31
+ Arstotzka.configure { json :@hash }
32
+ end
33
+
34
+ it do
35
+ expect(restaurant.dishes).to be_nil
36
+ end
37
+
38
+ context 'when setting default case to snake' do
39
+ before do
40
+ Arstotzka.configure { |c| c.case :snake }
41
+ end
42
+
43
+ it do
44
+ expect(restaurant.dishes)
45
+ .to eq(%w[
46
+ Goulash Spaghetti Pizza
47
+ ])
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Arstotzka::Config do
6
+ describe 'yard' do
7
+ subject(:config) { Arstotzka.config }
8
+
9
+ describe '#options' do
10
+ let(:overrides) { { klass: Person } }
11
+
12
+ let(:expected) do
13
+ {
14
+ after: false,
15
+ after_each: nil,
16
+ cached: false,
17
+ case: :snake,
18
+ compact: false,
19
+ default: nil,
20
+ flatten: false,
21
+ json: :json,
22
+ klass: Person,
23
+ type: :none
24
+ }
25
+ end
26
+
27
+ before do
28
+ Arstotzka.configure do |config|
29
+ config.case :snake
30
+ end
31
+ end
32
+
33
+ after { Arstotzka.reset_config }
34
+
35
+ it 'configure options to use snake case' do
36
+ expect(config.options(overrides).to_h).to eq(expected)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Arstotzka::Fetcher::Cache do
6
+ describe 'yard' do
7
+ let(:instance) { Object.new }
8
+
9
+ let(:options) do
10
+ Arstotzka::Options.new(
11
+ options_hash.merge(key: :x, instance: instance)
12
+ )
13
+ end
14
+
15
+ describe '#fetch' do
16
+ describe 'without cache option' do
17
+ subject(:cache) do
18
+ described_class.new do
19
+ (settings[:min]..settings[:max]).sum
20
+ end
21
+ end
22
+
23
+ let(:options_hash) { {} }
24
+ let(:settings) { { min: 1, max: 100 } }
25
+
26
+ it 'retrieves value from block' do
27
+ expect(cache.fetch).to eq(5050)
28
+ end
29
+
30
+ it 'retrieves every time' do
31
+ cache.fetch
32
+ settings[:max] = 10
33
+ expect(cache.fetch).to eq(55)
34
+ end
35
+ end
36
+
37
+ describe 'with simple cache option' do
38
+ subject(:cache) do
39
+ described_class.new(options) do
40
+ (settings[:min]..settings[:max]).sum if settings[:calculate]
41
+ end
42
+ end
43
+
44
+ let(:options_hash) { { cached: true } }
45
+ let(:settings) { { calculate: false, min: 1, max: 100 } }
46
+
47
+ it 'returns nil on first attempt' do
48
+ expect(cache.fetch).to be_nil
49
+ end
50
+
51
+ it 'recalculates when cache is nil' do
52
+ cache.fetch
53
+ settings[:calculate] = true
54
+
55
+ expect(cache.fetch).to eq(5050)
56
+ end
57
+
58
+ it ' does not recalculates when cache is not nil' do
59
+ cache.fetch
60
+ settings[:calculate] = true
61
+ cache.fetch
62
+ settings[:max] = 10
63
+
64
+ expect(cache.fetch).to eq(5050)
65
+ end
66
+ end
67
+
68
+ describe 'with full cache option' do
69
+ subject(:cache) do
70
+ described_class.new(options) do
71
+ (settings[:min]..settings[:max]).sum if settings[:calculate]
72
+ end
73
+ end
74
+
75
+ let(:options_hash) { { cached: :full } }
76
+ let(:settings) { { calculate: false, min: 1, max: 100 } }
77
+
78
+ it 'returns nil on first attempt' do
79
+ expect(cache.fetch).to be_nil
80
+ end
81
+
82
+ it 'does not recalculate when cache is nil' do
83
+ cache.fetch
84
+ settings[:calculate] = true
85
+
86
+ expect(cache.fetch).to be_nil
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -7,12 +7,11 @@ describe Arstotzka::FetcherBuilder do
7
7
  describe '#build' do
8
8
  subject(:builder) { described_class.new(options) }
9
9
 
10
- let(:options) { Arstotzka::Options.new(options_hash) }
11
10
  let(:fetcher) { builder.build(instance) }
12
11
  let(:instance) { MyModel.new(hash) }
13
12
 
14
- context 'with sample usage' do
15
- let(:options_hash) { { key: :id, path: :person } }
13
+ describe 'Building a simple fetcher' do
14
+ let(:options) { { key: :id, path: :person } }
16
15
 
17
16
  let(:hash) do
18
17
  {
@@ -27,8 +26,8 @@ describe Arstotzka::FetcherBuilder do
27
26
  end
28
27
  end
29
28
 
30
- context 'with passing full path' do
31
- let(:options_hash) do
29
+ describe 'Builder a fetcher using full path' do
30
+ let(:options) do
32
31
  {
33
32
  key: :player_ids,
34
33
  full_path: 'teams.players.person_id',
@@ -62,7 +61,7 @@ describe Arstotzka::FetcherBuilder do
62
61
  end
63
62
  end
64
63
 
65
- context 'when filtering the result' do
64
+ describe 'Post processing results' do
66
65
  let(:instance) { StarGazer.new(hash) }
67
66
  let(:hash) do
68
67
  {
@@ -75,15 +74,16 @@ describe Arstotzka::FetcherBuilder do
75
74
  ]
76
75
  }
77
76
  end
78
- let(:options_hash) do
77
+ let(:options) do
79
78
  { key: :stars, klass: Star, after: :only_yellow }
80
79
  end
81
80
 
82
81
  it 'builds a fetcher capable of fetching and filtering value' do
83
- expect(fetcher.fetch).to eq([
84
- Star.new(name: 'Sun', color: 'yellow'),
85
- Star.new(name: 'HB0124-C', color: 'yellow')
86
- ])
82
+ expect(fetcher.fetch)
83
+ .to eq([
84
+ Star.new(name: 'Sun', color: 'yellow'),
85
+ Star.new(name: 'HB0124-C', color: 'yellow')
86
+ ])
87
87
  end
88
88
  end
89
89
  end