arstotzka 1.3.2 → 1.4.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 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