yake 1.2.1 → 1.3.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: ca67b728ac7669680177b57f9ec3425073859d9e3fccc8e336e8c1d86ee903d9
4
- data.tar.gz: 8f02b1e165461fca8af9a36cd2ae1543ba31f49396c868a20af50ee459d394e6
3
+ metadata.gz: d461854504d327c8e6b363d968b1aebe460d65918a470db73fcab94f9ec43205
4
+ data.tar.gz: ddd0ae3a98dc95174c0f0bdde89c968d3d45af995c65e42bc0e13f5b430466e2
5
5
  SHA512:
6
- metadata.gz: 98cf4e930f7868468509a0e1b0fdca92ddf834c404ef087c11ed70361f358ea1dee9bf7b582f72b39a1b1583c6017a40caf5022b50452fc22608a0615c3513aa
7
- data.tar.gz: cec7cabf789420d27b88ae5cdfcfba5244422aaccf9a2fdac7e4911de180554543176c05d125123610c672e13cd922d2863e6a8ecc318487f6b5f54558a77c48
6
+ metadata.gz: 43fbd717b48b43c49f555b6a6176bb64595a75df6c250b30b851a2a29a6cd0d8fe8808a156f9c7411de8777a6564b49b57197244761d080ae8a90632971a4097
7
+ data.tar.gz: 37a8a171dc9ce1bed8c31a97c990cb5576b8302bcec08445b48f6e20850059998bc6c7f6d02723addb9b90fc3ae708682dec440557c6494e3581fedd50857e93
data/README.md CHANGED
@@ -2,8 +2,6 @@
2
2
 
3
3
  [![gem](https://img.shields.io/gem/v/yake?color=crimson&logo=rubygems&logoColor=eee&style=flat-square)](https://rubygems.org/gems/yake)
4
4
  [![rspec](https://img.shields.io/github/actions/workflow/status/amancevice/yake/rspec.yml?logo=github&style=flat-square)](https://github.com/amancevice/yake/actions/workflows/rspec.yml)
5
- [![coverage](https://img.shields.io/codeclimate/coverage/amancevice/yake?logo=code-climate&style=flat-square)](https://codeclimate.com/github/amancevice/yake/test_coverage)
6
- [![maintainability](https://img.shields.io/codeclimate/maintainability/amancevice/yake?logo=code-climate&style=flat-square)](https://codeclimate.com/github/amancevice/yake/maintainability)
7
5
 
8
6
  [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/smallweirdnumber)
9
7
 
@@ -179,7 +177,7 @@ end
179
177
 
180
178
  ### (Near) Zero Dependencies
181
179
 
182
- Finally, `yake` does not depend on any 3rd party gems. The only exceptions are the `ostruct` and `logger` gems, which are being removed from the Ruby stdlib in Ruby v3.5. This helps keep your Lambda packages slim & speedy.
180
+ Finally, `yake` does not depend on any 3rd party gems. This helps keep your Lambda packages slim & speedy.
183
181
 
184
182
  ## Support Helpers
185
183
 
@@ -191,6 +189,18 @@ Enable the helpers by requiring the `support` submodule:
191
189
  require 'yake/support'
192
190
  ```
193
191
 
192
+ `Array` helpers:
193
+
194
+ ```ruby
195
+ array = [{ a: 'b'}, { a: 'c' }, { a: 'd' }]
196
+
197
+ array.pluck(:a)
198
+ # => ["b", "c", "d"]
199
+
200
+ array.to_dynamodb
201
+ # => {:L=>[{:a=>{:S=>"b"}}, {:a=>{:S=>"c"}}, {:a=>{:S=>"d"}}]}
202
+ ```
203
+
194
204
  `Object` helpers:
195
205
 
196
206
  ```ruby
@@ -228,9 +238,6 @@ hash.deep_transform_keys!(&:to_s)
228
238
  { fizz: 'buzz' }.encode64
229
239
  # => "eyJmaXp6IjoiYnV6eiJ9\n"
230
240
 
231
- { fizz: 'buzz', jazz: 'fuzz' }.except(:buzz)
232
- # => { :fizz => 'buzz' }
233
-
234
241
  { fizz: 'buzz' }.strict_encode64
235
242
  # => "eyJmaXp6IjoiYnV6eiJ9"
236
243
 
data/lib/yake/api.rb CHANGED
@@ -7,10 +7,12 @@ require_relative 'errors'
7
7
 
8
8
  module Yake
9
9
  module API
10
+ ##
11
+ # Yake API DSL
10
12
  module DSL
11
13
  ##
12
- # Proxy handler for HTTP requests from Slack
13
- def route(event, context = nil, &block)
14
+ # Proxy handler for HTTP requests from API Gateway
15
+ def route(event, context = nil)
14
16
  # Extract route method
15
17
  method = event['routeKey']
16
18
  raise Yake::Errors::UndeclaredRoute, method unless respond_to?(method)
@@ -33,20 +35,20 @@ module Yake
33
35
  # Transform to API Gateway response
34
36
  def respond(status_code, body = nil, **headers)
35
37
  # Log response
36
- log = "RESPONSE [#{ status_code }] #{ body }"
38
+ log = "RESPONSE [#{status_code}] #{body}"
37
39
  Yake.logger&.send(status_code.to_i >= 400 ? :error : :info, log)
38
40
 
39
41
  # Set headers
40
42
  content_length = (body&.bytesize || 0).to_s
41
- to_s_downcase = -> (key) { key.to_s.downcase }
43
+ to_s_downcase = ->(key) { key.to_s.downcase }
42
44
  headers = {
43
45
  'content-length' => content_length,
44
46
  **(@headers || {}),
45
- **headers,
47
+ **headers
46
48
  }.transform_keys(&to_s_downcase).compact
47
49
 
48
50
  # Send response
49
- { statusCode: status_code, headers: headers, body: body }.compact
51
+ { statusCode: status_code, headers:, body: }.compact
50
52
  end
51
53
 
52
54
  ##
@@ -55,55 +57,13 @@ module Yake
55
57
  (@headers ||= {}).update(headers)
56
58
  end
57
59
 
58
- ##
59
- # Define ANY route
60
- def any(path, &block)
61
- define_singleton_method("ANY #{ path }") { |*args| instance_exec(*args, &block) }
62
- end
63
-
64
- ##
65
- # Define DELETE route
66
- def delete(path, &block)
67
- define_singleton_method("DELETE #{ path }") { |*args| instance_exec(*args, &block) }
68
- end
69
-
70
- ##
71
- # Define GET route
72
- def get(path, &block)
73
- define_singleton_method("GET #{ path }") { |*args| instance_exec(*args, &block) }
74
- end
75
-
76
- ##
77
- # Define HEAD route
78
- def head(path, &block)
79
- define_singleton_method("HEAD #{ path }") { |*args| instance_exec(*args, &block) }
80
- end
81
-
82
- ##
83
- # Define OPTIONS route
84
- def options(path, &block)
85
- define_singleton_method("OPTIONS #{ path }") { |*args| instance_exec(*args, &block) }
86
- end
87
-
88
- ##
89
- # Define PATCH route
90
- def patch(path, &block)
91
- define_singleton_method("PATCH #{ path }") { |*args| instance_exec(*args, &block) }
92
- end
93
-
94
- ##
95
- # Define POST route
96
- def post(path, &block)
97
- define_singleton_method("POST #{ path }") { |*args| instance_exec(*args, &block) }
98
- end
99
-
100
- ##
101
- # Define PUT route
102
- def put(path, &block)
103
- define_singleton_method("PUT #{ path }") { |*args| instance_exec(*args, &block) }
60
+ %w[ANY DELETE GET HEAD OPTIONS PATCH POST PUT].each do |verb|
61
+ define_method(verb.downcase) do |path, &block|
62
+ define_singleton_method("#{verb} #{path}") { |*args| instance_exec(*args, &block) }
63
+ end
104
64
  end
105
65
  end
106
66
  end
107
67
  end
108
68
 
109
- extend Yake::API::DSL
69
+ extend Yake::API::DSL # rubocop: disable Style/MixinUsage
data/lib/yake/datadog.rb CHANGED
@@ -5,23 +5,24 @@ require 'logger'
5
5
  require 'datadog/lambda'
6
6
  require 'yake'
7
7
 
8
+ ##
9
+ # Yake
8
10
  module Yake
9
11
  module Datadog
12
+ ##
13
+ # Datadog Logger Formatter
10
14
  class Formatter < ::Logger::Formatter
11
- Format = "[%s] %s %s %s %s\n"
15
+ Format = "[%s] %s %s %s %s\n" # rubocop: disable Naming/ConstantName
12
16
 
13
17
  def call(severity, time, progname, msg)
14
- Format % [
15
- severity,
16
- time.utc.strftime('%Y-%m-%dT%H:%M:%S.%LZ'),
17
- progname.nil? ? '-' : progname.split.last,
18
- ::Datadog::Tracing.log_correlation,
19
- msg2str(msg).strip,
20
- ]
18
+ format(Format, severity, time.utc.strftime('%Y-%m-%dT%H:%M:%S.%LZ'), progname.nil? ? '-' : progname.split.last,
19
+ ::Datadog::Tracing.log_correlation, msg2str(msg).strip)
21
20
  end
22
21
  end
23
22
 
24
- class MockContext < Struct.new(
23
+ ##
24
+ # Mock Lambda Context
25
+ MockContext = Struct.new(
25
26
  :clock_diff,
26
27
  :deadline_ms,
27
28
  :aws_request_id,
@@ -30,8 +31,8 @@ module Yake
30
31
  :log_stream_name,
31
32
  :function_name,
32
33
  :memory_limit_in_mb,
33
- :function_version)
34
-
34
+ :function_version
35
+ ) do
35
36
  def invoked_function_arn
36
37
  @invoked_function_arn ||= begin
37
38
  region = ENV['AWS_REGION'] || ENV['AWS_DEFAULT_REGION'] || 'us-east-1'
@@ -40,13 +41,15 @@ module Yake
40
41
  end
41
42
  end
42
43
 
44
+ ##
45
+ # Datadog DSL
43
46
  module DSL
44
47
  include Yake::DSL
45
48
 
46
49
  ##
47
50
  # Datadog handler wrapper
48
51
  def datadog(name, &block)
49
- define_method(name) do |event:nil, context:nil|
52
+ define_method(name) do |event: nil, context: nil|
50
53
  context ||= MockContext.new
51
54
  ::Datadog::Lambda.wrap(event, context) do
52
55
  Yake.wrap(event, context, &block)
@@ -59,4 +62,4 @@ module Yake
59
62
  logger.formatter = Datadog::Formatter.new
60
63
  end
61
64
 
62
- extend Yake::Datadog::DSL
65
+ extend Yake::Datadog::DSL # rubocop: disable Style/MixinUsage
data/lib/yake/dsl.rb CHANGED
@@ -2,14 +2,19 @@
2
2
 
3
3
  require 'json'
4
4
 
5
+ require_relative 'errors'
5
6
  require_relative 'logger'
6
7
 
8
+ ##
9
+ # Yake
7
10
  module Yake
11
+ ##
12
+ # Yake DSL
8
13
  module DSL
9
14
  ##
10
15
  # Lambda handler task wrapper
11
16
  def handler(name, &block)
12
- define_method(name) do |event:nil, context:nil|
17
+ define_method(name) do |event: nil, context: nil|
13
18
  Yake.wrap(event, context, &block)
14
19
  end
15
20
  end
@@ -35,12 +40,12 @@ module Yake
35
40
  end
36
41
 
37
42
  class << self
38
- def wrap(event = nil, context = nil, &block)
43
+ def wrap(event = nil, context = nil, &) # rubocop: disable Metrics/AbcSize
39
44
  original_progname = logger.progname
40
45
  logger.progname = context&.aws_request_id
41
- jsonify = -> (obj) { pretty? ? JSON.pretty_generate(obj) : obj.to_json }
42
- log_return = -> (res) { logger.info("RETURN #{ jsonify === res }") }
43
- logger.info("EVENT #{ jsonify === event }")
46
+ jsonify = ->(obj) { pretty? ? JSON.pretty_generate(obj) : obj.to_json }
47
+ log_return = ->(res) { logger.info("RETURN #{jsonify.call(res)}") }
48
+ logger.info("EVENT #{jsonify.call(event)}")
44
49
  (yield(event, context) if block_given?).tap(&log_return)
45
50
  ensure
46
51
  logger.progname = original_progname
@@ -48,4 +53,4 @@ module Yake
48
53
  end
49
54
  end
50
55
 
51
- extend Yake::DSL
56
+ extend Yake::DSL # rubocop: disable Style/MixinUsage
data/lib/yake/errors.rb CHANGED
@@ -1,23 +1,38 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Yake
4
+ ##
5
+ # Custom Errors
4
6
  module Errors
5
7
  class Error < StandardError; end
6
8
 
9
+ ##
10
+ # Error not found by code
11
+ class CodeNotFound < Error
12
+ def initialize(code = nil)
13
+ super("No Error class for code '#{code}'")
14
+ end
15
+ end
16
+
17
+ ##
18
+ # Event uses undeclared route
7
19
  class UndeclaredRoute < Error
8
20
  def initialize(method = nil)
9
- super("No route declared for '#{ method }'")
21
+ super("No route declared for '#{method}'")
10
22
  end
11
23
  end
12
24
 
25
+ ##
26
+ # Bad logging setting
13
27
  class UnknownLoggingSetting < Error
14
28
  def initialize(method = nil)
15
- super("Unknown logging setting '#{ method }'. Use :on or :off")
29
+ super("Unknown logging setting '#{method}'. Use :on or :off")
16
30
  end
17
31
  end
18
32
 
19
33
  # HTTP Errors
20
34
 
35
+ # rubocop: disable Style/CommentedKeyword
21
36
  class BadRequest < Error; end # HTTP 400
22
37
  class Unauthorized < Error; end # HTTP 401
23
38
  class PaymentRequired < Error; end # HTTP 402
@@ -59,6 +74,7 @@ module Yake
59
74
  class LoopDetected < Error; end # HTTP 508
60
75
  class NotExtended < Error; end # HTTP 510
61
76
  class NetworkAuthenticationRequired < Error; end # HTTP 511
77
+ # rubocop: enable Style/CommentedKeyword
62
78
 
63
79
  ERRORS = {
64
80
  '400' => BadRequest,
@@ -101,11 +117,13 @@ module Yake
101
117
  '507' => InsufficientStorage,
102
118
  '508' => LoopDetected,
103
119
  '510' => NotExtended,
104
- '511' => NetworkAuthenticationRequired,
105
- }
120
+ '511' => NetworkAuthenticationRequired
121
+ }.freeze
106
122
 
107
123
  def self.[](code)
108
124
  ERRORS.fetch(code.to_s)
125
+ rescue KeyError
126
+ raise CodeNotFound.new(code)
109
127
  end
110
128
  end
111
129
  end
data/lib/yake/logger.rb CHANGED
@@ -3,7 +3,11 @@
3
3
  require 'json'
4
4
  require 'logger'
5
5
 
6
+ ##
7
+ # Yake
6
8
  module Yake
9
+ ##
10
+ # Yake Logger
7
11
  module Logger
8
12
  attr_writer :logger
9
13
 
@@ -17,15 +21,13 @@ module Yake
17
21
  end
18
22
  end
19
23
 
24
+ ##
25
+ # Yake Logger Formatter
20
26
  class Formatter < ::Logger::Formatter
21
- Format = "%s %s %s\n"
22
-
23
- def call(severity, time, progname, msg)
24
- Format % [
25
- severity,
26
- progname.nil? ? '-' : "RequestId: #{ progname }",
27
- msg2str(msg).strip
28
- ]
27
+ Format = "%s %s %s\n" # rubocop: disable Naming/ConstantName
28
+
29
+ def call(severity, _time, progname, msg)
30
+ format(Format, severity, progname.nil? ? '-' : "RequestId: #{progname}", msg2str(msg).strip)
29
31
  end
30
32
  end
31
33
  end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # Array helpers
5
+ class Array
6
+ def pluck(key) = map { |x| x[key] }
7
+ def to_dynamodb = { L: map(&:to_dynamodb) }
8
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # Hash helpers
5
+ class Hash
6
+ def deep_keys = map { |k, v| v.respond_to?(:deep_keys) ? [k] + v.deep_keys : k }.flatten
7
+ def deep_sort = sort.to_h { |k, v| [k, v.try(:deep_sort) { |x| x }] }
8
+ def deep_transform_keys(&) = deep_transform(:transform_keys, &)
9
+ def deep_transform_keys!(&) = deep_transform(:transform_keys!, &)
10
+ def encode64 = to_json.encode64
11
+ def strict_encode64 = to_json.strict_encode64
12
+ def stringify_names = deep_transform_keys(&:to_s)
13
+ def stringify_names! = deep_transform_keys!(&:to_s)
14
+ def symbolize_names = deep_transform_keys(&:to_sym)
15
+ def symbolize_names! = deep_transform_keys!(&:to_sym)
16
+ def to_form = URI.encode_www_form(self)
17
+ def to_json_sorted = deep_sort.to_json
18
+ def to_struct = Struct.new(*keys.map(&:to_sym)).new(*values)
19
+
20
+ ##
21
+ # Adapted from ActiveSupport Hash#deep_merge
22
+ # https://github.com/rails/rails/blob/f95c0b7e96eb36bc3efc0c5beffbb9e84ea664e4/activesupport/lib/active_support/core_ext/hash/deep_merge.rb
23
+ def deep_merge(other, &block) # rubocop: disable Metrics/MethodLength
24
+ merge(other) do |key, a, b|
25
+ if a.is_a?(Hash) && b.is_a?(Hash)
26
+ a.deep_merge(b, &block)
27
+ elsif a.is_a?(Array) && b.is_a?(Array)
28
+ a + b
29
+ elsif block_given?
30
+ yield key, a, b
31
+ else
32
+ b
33
+ end
34
+ end
35
+ end
36
+
37
+ def to_deep_struct # rubocop: disable Metrics/MethodLength
38
+ to_struct.tap do |struct|
39
+ struct.to_h.each do |key, val|
40
+ struct[key] =
41
+ if val.is_a?(Array)
42
+ val.map { |i| i.respond_to?(:to_deep_struct) ? i.to_deep_struct : i }
43
+ elsif val.is_a?(Hash)
44
+ val.to_deep_struct
45
+ else
46
+ val
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ def to_dynamodb
53
+ map do |key, val|
54
+ { key => val.is_a?(Hash) ? { M: val.to_dynamodb } : val.to_dynamodb }
55
+ end.reduce(&:merge)
56
+ end
57
+
58
+ def to_h_from_dynamodb # rubocop: disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
59
+ decode = lambda do |i|
60
+ type, val = i.first
61
+ case type.to_sym
62
+ when :BOOL, :S then val
63
+ when :NULL then nil
64
+ when :NS then Set.new(val.map { |x| x =~ /^[0-9]+$/ ? x.to_i : x.to_f })
65
+ when :SS then Set.new(val)
66
+ when :N then val =~ /^[0-9]+$/ ? val.to_i : val.to_f
67
+ when :L then val.map(&decode)
68
+ when :M then val.transform_values(&decode)
69
+ end
70
+ end
71
+ map do |key, val|
72
+ { key => decode.call(val) }
73
+ end.reduce(&:merge)
74
+ end
75
+
76
+ private
77
+
78
+ def deep_transform(method, &block)
79
+ f = ->(x) { x.respond_to?(:"deep_#{method}") ? x.send(:"deep_#{method}", &block) : x }
80
+ if block_given?
81
+ send(method, &block).to_h do |key, val|
82
+ [key, val.is_a?(Array) ? val.map(&f) : val.then(&f)]
83
+ end
84
+ else
85
+ self
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # Integer helpers
5
+ class Integer
6
+ def weeks = days * 7
7
+ def days = hours * 24
8
+ def hours = minutes * 60
9
+ def minutes = seconds * 60
10
+ def seconds = self
11
+ def utc = UTC.at(self)
12
+
13
+ alias second seconds
14
+ alias minute minutes
15
+ alias hour hours
16
+ alias day days
17
+ alias week weeks
18
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # Numeric helpers
5
+ class Numeric
6
+ def to_dynamodb = { N: to_s }
7
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # Object helpers
5
+ class Object
6
+ def try(method, *, **, &)
7
+ public_send(method, *, **)
8
+ rescue NoMethodError
9
+ block_given? ? yield(self) : nil
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # String helpers
5
+ class String
6
+ def /(other) = File.join(self, other.to_s)
7
+ def camel_case = split(/[_ ]/).map(&:capitalize).join
8
+ def decode64 = unpack1('m')
9
+ def encode64 = [self].pack('m')
10
+ def md5sum = Digest::MD5.hexdigest(self)
11
+ def sha1sum = Digest::SHA1.hexdigest(self)
12
+ def snake_case = gsub(/([a-z])([A-Z])/, '\1_\2').gsub(/ /, '_').downcase
13
+ def strict_decode64 = unpack1('m0')
14
+ def strict_encode64 = [self].pack('m0')
15
+ def to_dynamodb = { S: self }
16
+ def to_h_from_json(...) = JSON.parse(self, ...)
17
+ def to_h_from_form = URI.decode_www_form(self).to_h
18
+ def utc = UTC.parse(self)
19
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # Symbol helpers
5
+ class Symbol
6
+ def camel_case = to_s.camel_case.to_sym
7
+ def snake_case = to_s.snake_case.to_sym
8
+ def to_dynamodb = { S: to_s }
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # UTC time
5
+ class UTC < Time
6
+ def initialize(...) = super.utc
7
+ def self.at(...) = super.utc
8
+ def self.now = super.utc
9
+ end
data/lib/yake/support.rb CHANGED
@@ -5,141 +5,11 @@ require 'json'
5
5
  require 'time'
6
6
  require 'uri'
7
7
 
8
- class Array
9
- def to_dynamodb = { L: map(&:to_dynamodb) }
10
- end
11
-
12
- class Hash
13
- def deep_keys = map { |k,v| v.respond_to?(:deep_keys) ? [k] + v.deep_keys : k }.flatten
14
- def deep_sort = sort.map { |k,v| [ k, v.try(:deep_sort) { |x| x } ] }.to_h
15
- def deep_transform_keys(&block) = deep_transform(:transform_keys, &block)
16
- def deep_transform_keys!(&block) = deep_transform(:transform_keys!, &block)
17
- def encode64 = to_json.encode64
18
- def except(*keys) = reject { |key,_| keys.include? key }
19
- def strict_encode64 = to_json.strict_encode64
20
- def stringify_names = deep_transform_keys(&:to_s)
21
- def stringify_names! = deep_transform_keys!(&:to_s)
22
- def symbolize_names = deep_transform_keys(&:to_sym)
23
- def symbolize_names! = deep_transform_keys!(&:to_sym)
24
- def to_form = URI.encode_www_form(self)
25
- def to_json_sorted = deep_sort.to_json
26
- def to_struct = Struct.new(*keys.map(&:to_sym)).new(*values)
27
-
28
- ##
29
- # Adapted from ActiveSupport Hash#deep_merge
30
- # https://github.com/rails/rails/blob/f95c0b7e96eb36bc3efc0c5beffbb9e84ea664e4/activesupport/lib/active_support/core_ext/hash/deep_merge.rb
31
- def deep_merge(other, &block)
32
- merge(other) do |key, a, b|
33
- if a.is_a?(Hash) && b.is_a?(Hash)
34
- a.deep_merge(b, &block)
35
- elsif a.is_a?(Array) && b.is_a?(Array)
36
- a + b
37
- elsif block_given?
38
- yield key, a, b
39
- else
40
- b
41
- end
42
- end
43
- end
44
-
45
- def to_deep_struct
46
- to_struct.tap do |struct|
47
- struct.to_h.each do |key, val|
48
- struct[key] = if val.is_a?(Array)
49
- val.map do |item|
50
- item.respond_to?(:to_deep_struct) ? item.to_deep_struct : item
51
- end
52
- elsif val.is_a?(Hash)
53
- val.to_deep_struct
54
- else
55
- val
56
- end
57
- end
58
- end
59
- end
60
-
61
- def to_dynamodb
62
- map do |key, val|
63
- { key => val.is_a?(Hash) ? { M: val.to_dynamodb } : val.to_dynamodb }
64
- end.reduce(&:merge)
65
- end
66
-
67
- def to_h_from_dynamodb
68
- decode = -> (i) do
69
- type, val = i.first
70
- case type.to_sym
71
- when :S then val
72
- when :N then val =~ /^[0-9]+$/ ? val.to_i : val.to_f
73
- when :L then val.map(&decode)
74
- when :M then val.transform_values(&decode)
75
- end
76
- end
77
- map do |key, val|
78
- { key => decode === val }
79
- end.reduce(&:merge)
80
- end
81
-
82
- private
83
-
84
- def deep_transform(method, &block)
85
- f = -> (x) { x.respond_to?(:"deep_#{method}") ? x.send(:"deep_#{method}", &block) : x }
86
- block_given? ? send(method, &block).map do |key, val|
87
- [key, val.is_a?(Array) ? val.map(&f) : val.then(&f)]
88
- end.to_h : self
89
- end
90
- end
91
-
92
- class Numeric
93
- def to_dynamodb = { N: to_s }
94
- end
95
-
96
- class Integer
97
- def weeks = days * 7
98
- def days = hours * 24
99
- def hours = minutes * 60
100
- def minutes = seconds * 60
101
- def seconds = self
102
- def utc = UTC.at(self)
103
-
104
- alias :second :seconds
105
- alias :minute :minutes
106
- alias :hour :hours
107
- alias :day :days
108
- alias :week :weeks
109
- end
110
-
111
- class Object
112
- def try(method, *args, **kwargs, &block)
113
- send(method, *args, **kwargs)
114
- rescue
115
- block_given? ? yield(self) : nil
116
- end
117
- end
118
-
119
- class String
120
- def /(path) = File.join(self, path.to_s)
121
- def camel_case = split(/[_ ]/).map(&:capitalize).join
122
- def decode64 = self.unpack1('m')
123
- def encode64 = [self].pack('m')
124
- def md5sum = Digest::MD5.hexdigest(self)
125
- def sha1sum = Digest::SHA1.hexdigest(self)
126
- def snake_case = gsub(/([a-z])([A-Z])/, '\1_\2').gsub(/ /, '_').downcase
127
- def strict_decode64 = self.unpack1('m0')
128
- def strict_encode64 = [self].pack('m0')
129
- def to_dynamodb = { S: self }
130
- def to_h_from_json(...) = JSON.parse(self, ...)
131
- def to_h_from_form = URI.decode_www_form(self).to_h
132
- def utc = UTC.parse(self)
133
- end
134
-
135
- class Symbol
136
- def camel_case = to_s.camel_case.to_sym
137
- def snake_case = to_s.snake_case.to_sym
138
- def to_dynamodb = { S: to_s }
139
- end
140
-
141
- class UTC < Time
142
- def initialize(...) = super.utc
143
- def self.at(...) = super.utc
144
- def self.now = super.utc
145
- end
8
+ require_relative 'support/array'
9
+ require_relative 'support/hash'
10
+ require_relative 'support/integer'
11
+ require_relative 'support/numeric'
12
+ require_relative 'support/object'
13
+ require_relative 'support/string'
14
+ require_relative 'support/symbol'
15
+ require_relative 'support/utc'
data/lib/yake/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Yake
4
- VERSION = '1.2.1'
4
+ VERSION = '1.3.0'
5
5
  end
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yake
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Mancevice
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-02-03 00:00:00.000000000 Z
11
+ date: 2026-06-21 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: ostruct
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: logger
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -54,11 +40,20 @@ files:
54
40
  - lib/yake/errors.rb
55
41
  - lib/yake/logger.rb
56
42
  - lib/yake/support.rb
43
+ - lib/yake/support/array.rb
44
+ - lib/yake/support/hash.rb
45
+ - lib/yake/support/integer.rb
46
+ - lib/yake/support/numeric.rb
47
+ - lib/yake/support/object.rb
48
+ - lib/yake/support/string.rb
49
+ - lib/yake/support/symbol.rb
50
+ - lib/yake/support/utc.rb
57
51
  - lib/yake/version.rb
58
52
  homepage: https://github.com/amancevice/yake
59
53
  licenses:
60
54
  - MIT
61
- metadata: {}
55
+ metadata:
56
+ rubygems_mfa_required: 'true'
62
57
  post_install_message:
63
58
  rdoc_options: []
64
59
  require_paths:
@@ -74,7 +69,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
74
69
  - !ruby/object:Gem::Version
75
70
  version: '0'
76
71
  requirements: []
77
- rubygems_version: 3.5.16
72
+ rubygems_version: 3.5.22
78
73
  signing_key:
79
74
  specification_version: 4
80
75
  summary: Rake-like DSL for declaring AWS Lambda function handlers