arstotzka 1.3.2 → 1.4.0

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: fc52a24a605aeff67f5a310bf8e6bc7dbe300374ba03678ef4abe68f05ae4f4e
4
- data.tar.gz: 37ec2565487d9b560d1da8571b12dc6d562a888366e8d8ecb368089ddbf2cb33
3
+ metadata.gz: 3343d391090a1c5e806d56c9eb97790a79a04fbc24b707384a71024c3f894879
4
+ data.tar.gz: da14356086e54f211d32a0725de04bd8ba01a2bb7c767ced8e17519f47f6fb37
5
5
  SHA512:
6
- metadata.gz: 995a859fdd57fc6a32cff22aec0ae542b22148de6ab5a16497e62acec94249e7c56e61e39b8ca336ed2383ebae8ec0efee3e8f8d4fd18366795a66cf88ce6baf
7
- data.tar.gz: 55376d536beeb947697540cbdd3a8909b17e85d86beb5cde27d0535975ce59380cf49503d3eabbf3e7af7ae51b6eb77d8c1fce6c3dadc3f8c2b2212b65a1ee36
6
+ metadata.gz: 4dabdf1acd44e98e8884a0106d84bd6e1f6e3cd33940b0a777049f66d58529757223dbf28e50ff6717764fe025905bf3d3b5d5a38ee710357fc891b3e6c6de61
7
+ data.tar.gz: ed2fcefdd16da6ac23e8439a84f8158ad271da23385e6560f97197eafc1ba15b6d3a6150be56493767a4f06a19b82b6790386343a409f9b51d76afb3987fc966
data/.circleci/config.yml CHANGED
@@ -2,7 +2,7 @@ version: 2
2
2
  jobs:
3
3
  build:
4
4
  docker:
5
- - image: darthjee/circleci_ruby_gems:0.0.2
5
+ - image: darthjee/circleci_ruby_gems:0.1.0
6
6
  steps:
7
7
  - checkout
8
8
  - run:
data/Dockerfile CHANGED
@@ -1,6 +1,26 @@
1
- FROM darthjee/ruby_gems:0.0.2
1
+ FROM darthjee/ruby_gems:0.1.0 as base
2
+ FROM darthjee/scripts:0.0.2 as scripts
3
+
4
+ ######################################
5
+
6
+ FROM base as builder
2
7
 
3
- USER app
4
8
  COPY --chown=app ./ /home/app/app/
9
+ COPY --chown=app:app --from=scripts /home/scripts/ ./
10
+
11
+ ENV HOME_DIR /home/app
12
+ RUN /bin/bash bundle_builder.sh
5
13
 
6
- RUN bundle install
14
+ #######################
15
+ #FINAL IMAGE
16
+ FROM base
17
+
18
+ USER root
19
+
20
+ COPY --chown=app:app --from=builder /home/app/bundle/gems /usr/local/bundle/gems
21
+ COPY --chown=app:app --from=builder /home/app/bundle/cache /usr/local/bundle/cache
22
+ COPY --chown=app:app --from=builder /home/app/bundle/specifications /usr/local/bundle/specifications
23
+ COPY --chown=app:app --from=builder /home/app/bundle/bin /usr/local/bundle/bin
24
+ COPY --chown=app:app --from=builder /home/app/bundle/extensions /usr/local/bundle/extensions
25
+
26
+ USER app
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.3.2
22
+ https://www.rubydoc.info/gems/arstotzka/1.4.0
23
23
 
24
24
  Instalation
25
25
  ---------------
@@ -97,13 +97,19 @@ Options
97
97
  - after: Name of a method to be called after on the values returned
98
98
  - after_each: Name of a method to be called after each result
99
99
  - cached: Indicator that, once the value has been fetched, it should be cached (false by default)
100
+ - false : no cache
101
+ - true : simple cache where nil values are not considerated cached
102
+ - :full : full cache where even nil values are cached
100
103
  - case: Case of the keys from the json (lower_camel by default)
104
+ - :snake : snakecase (eg. `the_key`)
105
+ - :lower_camel : lower cammel case (eg. `theKey`)
106
+ - :upper_camel : upper cammel case (eg. `TheKey`)
101
107
  - compact: Indicator telling to ignore nil values inside array (false by default)
102
108
  - default: Default value (prior to casting and wrapping, see [Default](#default))
103
109
  - flatten: Indicator telling that to flattern the resulting array (false by default)
104
110
  - full_path: Full path to fetch the value (empty by default)
105
111
  - klass: Class to be used when wrapping the final value
106
- - json: Method that contains the hash to be parsed (json by default)
112
+ - json: Method that contains the hash to be parsed (`:json` by default)
107
113
  - path: Path where to find the sub hash that contains the key (empty by default)
108
114
  - type: Type that the value must be cast into ([TypeCast](#typecast))
109
115
 
@@ -195,3 +201,42 @@ star_gazer.favorite_star.name # returns "Sun"
195
201
  star_gazer.favorite_star.class # returns Star
196
202
  ```
197
203
 
204
+ Configuration
205
+ -------------
206
+ Arstotzka can be configured changing the default options
207
+
208
+ ```ruby
209
+ class Restaurant
210
+ include Arstotzka
211
+
212
+ expose :dishes, path: 'restaurant.complete_meals'
213
+
214
+ def initialize(hash)
215
+ @hash = hash
216
+ end
217
+ end
218
+
219
+ hash = {
220
+ restaurant: {
221
+ complete_meals: {
222
+ dishes: %w[
223
+ Goulash
224
+ Spaghetti
225
+ Pizza
226
+ ]
227
+ }
228
+ }
229
+ }
230
+
231
+ restaurant = Restaurant.new(hash)
232
+ restaurant.dishes # raises NoMethodError as json method is
233
+ # is not defined in Restaurant
234
+
235
+ Arstotzka.configure { json :@hash }
236
+
237
+ restaurant.dishes # returns nil as default case is lower_camel
238
+
239
+ Arstotzka.configure { |c| c.case :snake }
240
+
241
+ restaurant.dishes # return %s[Goulash Spaghetti Pizza]
242
+ ```
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.2.1'
23
+ gem.add_runtime_dependency 'sinclair', '>= 1.4.0'
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
@@ -24,6 +24,8 @@ rules:
24
24
  - Arstotzka::Exception::FetcherBuilderNotFound#attribute
25
25
  - Arstotzka::Exception::FetcherBuilderNotFound#klass
26
26
  - Arstotzka::Fetcher#options
27
+ - Arstotzka::Fetcher::Cache#block
28
+ - Arstotzka::Fetcher::Cache#options
27
29
  - Arstotzka::FetcherBuilder#options
28
30
  - Arstotzka::KeyReader#base_key
29
31
  - Arstotzka::KeyReader#hash
@@ -42,6 +44,9 @@ rules:
42
44
  - Arstotzka::Exception::FetcherBuilderNotFound#attribute
43
45
  - Arstotzka::Exception::FetcherBuilderNotFound#klass
44
46
  - Arstotzka::Fetcher#options
47
+ - Arstotzka::Fetcher::Cache#block
48
+ - Arstotzka::Fetcher::Cache#options
49
+ - Arstotzka::Fetcher::Cache#initialize
45
50
  - Arstotzka::FetcherBuilder#options
46
51
  - Arstotzka::KeyReader#base_key
47
52
  - Arstotzka::KeyReader#hash
data/lib/arstotzka.rb CHANGED
@@ -164,7 +164,10 @@ require 'sinclair'
164
164
  # @see Arstotzka::MethodBuilder
165
165
  # @see Arstotzka::ClassMethods
166
166
  module Arstotzka
167
+ require 'arstotzka/config'
168
+
167
169
  extend ActiveSupport::Concern
170
+ extend Sinclair::Configurable
168
171
 
169
172
  autoload :Base, 'arstotzka/base'
170
173
  autoload :ClassMethods, 'arstotzka/class_methods'
@@ -179,4 +182,6 @@ module Arstotzka
179
182
  autoload :Reader, 'arstotzka/reader'
180
183
  autoload :TypeCast, 'arstotzka/type_cast'
181
184
  autoload :Wrapper, 'arstotzka/wrapper'
185
+
186
+ configurable_by Arstotzka::Config
182
187
  end
@@ -18,7 +18,7 @@ module Arstotzka
18
18
  # @return [Arstotzka::Options]
19
19
  def options=(options)
20
20
  @options = if options.is_a?(Hash)
21
- Options.new(options)
21
+ Arstotzka.config.options(options)
22
22
  else
23
23
  options
24
24
  end
@@ -100,8 +100,7 @@ module Arstotzka
100
100
  # https://www.rubydoc.info/gems/activesupport/5.2.2/ActiveSupport/Concern
101
101
  # ActiveSupport::Concern
102
102
  def expose(*attr_names, **options_hash)
103
- options = Options.new(options_hash.symbolize_keys)
104
- MethodBuilder.new(attr_names.map(&:to_sym), self, options).build
103
+ MethodBuilder.new(attr_names.map(&:to_sym), self, options_hash).build
105
104
  end
106
105
 
107
106
  # @private
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Arstotzka
4
+ # @api public
5
+ #
6
+ # Arstotzka configuration
7
+ #
8
+ # Configuration is
9
+ #
10
+ # @see https://www.rubydoc.info/gems/sinclair/1.4.0/Sinclair/Config Sinclair::Config
11
+ #
12
+ # @example (see #options)
13
+ class Config < Sinclair::Config
14
+ DEFAULT_CONFIGS = {
15
+ after: false,
16
+ after_each: nil,
17
+ cached: false,
18
+ case: :lower_camel,
19
+ compact: false,
20
+ default: nil,
21
+ flatten: false,
22
+ json: :json,
23
+ klass: nil,
24
+ type: :none
25
+ }.freeze
26
+
27
+ add_configs DEFAULT_CONFIGS
28
+
29
+ # @api private
30
+ #
31
+ # Returns a new instance of {Options}
32
+ #
33
+ # the new instance will have it's values as a merge
34
+ # from configuration and given options_hash
35
+ #
36
+ # @param options_hash [Hash] options override
37
+ #
38
+ # @return [Options]
39
+ #
40
+ # @example Generating options
41
+ # Arstotzka.configure do |config|
42
+ # config.case :snake
43
+ # end
44
+ #
45
+ # config = Arstotzka.config
46
+ # options = config.options(klass: Person)
47
+ #
48
+ # options.to_h
49
+ # # returns
50
+ # # {
51
+ # # after: false,
52
+ # # after_each: nil,
53
+ # # cached: false,
54
+ # # case: :snake,
55
+ # # compact: false,
56
+ # # default: nil,
57
+ # # flatten: false,
58
+ # # json: :json,
59
+ # # klass: Person,
60
+ # # type: :none
61
+ # # }
62
+ def options(options_hash = {})
63
+ Options.new(
64
+ to_hash.symbolize_keys.merge(
65
+ options_hash.symbolize_keys
66
+ )
67
+ )
68
+ end
69
+ end
70
+ end
@@ -8,15 +8,17 @@ module Arstotzka
8
8
  class Fetcher
9
9
  include Base
10
10
 
11
+ autoload :Cache, 'arstotzka/fetcher/cache'
12
+
11
13
  # Creates an instance of Artotzka::Fetcher
12
14
  #
13
15
  # @overload iniitalize(options_hash = {})
14
16
  # @param options_hash [Hash] options for {Crawler}, {Wrapper},
15
- # {Reader} and {HashReader}
17
+ # {Reader}, {Cache} and {HashReader}
16
18
  #
17
19
  # @overload iniitalize(options)
18
20
  # @param options [Arstotzka::Options] options for {Crawler}, {Wrapper},
19
- # {Reader} and {HashReader}
21
+ # {Reader}, {Cache} and {HashReader}
20
22
  def initialize(options_hash = {})
21
23
  self.options = options_hash
22
24
  end
@@ -82,10 +84,9 @@ module Arstotzka
82
84
  # # Transaction.new(value: 50.23, type: 'income')
83
85
  # # ]
84
86
  def fetch
85
- value = crawler.value(hash)
86
- value.flatten! if flatten && value.is_a?(Array)
87
- value = instance.send(after, value) if after
88
- value
87
+ Cache.new(options) do
88
+ fetch_value
89
+ end.fetch
89
90
  end
90
91
 
91
92
  # Checks if other equals self
@@ -110,6 +111,20 @@ module Arstotzka
110
111
  delegate :wrap, to: :wrapper
111
112
  delegate :hash, to: :hash_reader
112
113
 
114
+ # @private
115
+ #
116
+ # fetch value from Hash
117
+ #
118
+ # Value is fetched trhough the usage of {Crawler},
119
+ # and wrapped with {Wrapper}
120
+ #
121
+ # @return [Object]
122
+ def fetch_value
123
+ value = crawler.value(hash)
124
+ value.flatten! if flatten && value.is_a?(Array)
125
+ after ? instance.send(after, value) : value
126
+ end
127
+
113
128
  # @private
114
129
  #
115
130
  # Returns an instance of Aristotzka::Craler
@@ -131,7 +146,7 @@ module Arstotzka
131
146
  #
132
147
  # @return [Arstotzka::Wrapper] the wrapper
133
148
  def wrapper
134
- @wrapper ||= Wrapper.new(options.merge(instance: instance))
149
+ @wrapper ||= Wrapper.new(options)
135
150
  end
136
151
 
137
152
  # @api private
@@ -0,0 +1,154 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Arstotzka
4
+ class Fetcher
5
+ # @api private
6
+ #
7
+ # Class responsible for reading instance variables
8
+ # when cached option is given.
9
+ #
10
+ # When the "cache" is not accepted, block will be called
11
+ # to determinate the value to be returned also caching
12
+ # it in an instance variable
13
+ class Cache
14
+ include Base
15
+
16
+ # @param block [Proc] block to be executed in case
17
+ # variable is not cached
18
+ #
19
+ # @overload initialize(options, &block)
20
+ # @param options [Arstotzka::Options] options passed
21
+ # as options object
22
+ #
23
+ # @overload initialize(options_hash, &block)
24
+ # @param options_hash [Hash] opttions passed as hash
25
+ def initialize(options_hash = {}, &block)
26
+ self.options = options_hash
27
+ @block = block
28
+ end
29
+
30
+ # Fetches value from instance or block
31
+ #
32
+ # When cached option is given, fetches value
33
+ # from cache, and in case of failure, retrieves
34
+ # value from block given in the initialization
35
+ #
36
+ # @yield runs the block given in the initialization
37
+ # when the value was not found in the cache
38
+ #
39
+ # @return [Object]
40
+ #
41
+ # @example Without cache option
42
+ # settings = { min: 1, max: 100 }
43
+ # instance = Object.new
44
+ #
45
+ # options = Arstotzka::Options.new(
46
+ # key: :x, instance: instance
47
+ # )
48
+ #
49
+ # cache = Arstotzka::Fetcher::Cache.new do
50
+ # (settings[:min]..settings[:max]).sum
51
+ # end
52
+ #
53
+ # cache.fetch # returns 5050
54
+ # settings[:max] = 10
55
+ # cache.fetch # returns 555
56
+ #
57
+ # @example With simple cache option
58
+ # settings = { calculate: false, min: 1, max: 100 }
59
+ # instance = Object.new
60
+ #
61
+ # options = Arstotzka::Options.new(
62
+ # key: :x, instance: instance, cached: true
63
+ # )
64
+ #
65
+ # cache = Arstotzka::Fetcher::Cache.new do
66
+ # if settings[:calculate]
67
+ # (settings[:min]..settings[:max]).sum
68
+ # end
69
+ # end
70
+ #
71
+ # cache.fetch # returns nil (which is not considered cache)
72
+ # settings[:calculate] = true
73
+ # cache.fetch # returns 5050
74
+ # settings[:max] = 10
75
+ # cache.fetch # returns 5050 from cache
76
+ #
77
+ # @example With full cache option
78
+ # settings = { calculate: false, min: 1, max: 100 }
79
+ # instance = Object.new
80
+ #
81
+ # options = Arstotzka::Options.new(
82
+ # key: :x, instance: instance, cached: :full
83
+ # )
84
+ #
85
+ # cache = Arstotzka::Fetcher::Cache.new do
86
+ # if settings[:calculate]
87
+ # (settings[:min]..settings[:max]).sum
88
+ # end
89
+ # end
90
+ #
91
+ # cache.fetch # returns nil
92
+ # settings[:calculate] = true
93
+ # cache.fetch # returns nil from cache
94
+ def fetch
95
+ if cached
96
+ fetch_with_cache
97
+ else
98
+ block.call
99
+ end
100
+ end
101
+
102
+ private
103
+
104
+ attr_reader :block, :options
105
+ delegate :cached, :key, :instance, to: :options
106
+
107
+ # @private
108
+ #
109
+ # Checks and retrieve value from cache
110
+ #
111
+ # when the value is not found in cache,
112
+ # block is called and it's value is cached
113
+ # and returned
114
+ #
115
+ # @return [Object]
116
+ def fetch_with_cache
117
+ if cached?
118
+ fetch_from_cache
119
+ else
120
+ instance.instance_variable_set("@#{key}", block.call)
121
+ end
122
+ end
123
+
124
+ # @private
125
+ #
126
+ # Returns the value from the instance variable (cache)
127
+ #
128
+ # the instance variable name is the same name of
129
+ # options.key (which is the same name of the method
130
+ # created in the instance by {MethodBuilder}
131
+ #
132
+ # @return [Object]
133
+ def fetch_from_cache
134
+ instance.instance_variable_get("@#{key}")
135
+ end
136
+
137
+ # @private
138
+ #
139
+ # Checks if value is present on cache
140
+ #
141
+ # The presence depends on the type of the cache
142
+ # - +true+ : nil values are considered not cached
143
+ # - +:full+ : nil instance variables are considered cached
144
+ # values
145
+ def cached?
146
+ if cached == :full
147
+ instance.instance_variable_defined?("@#{key}")
148
+ else
149
+ instance.instance_variable_get("@#{key}")
150
+ end
151
+ end
152
+ end
153
+ end
154
+ end