yake 1.2.0 → 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: 1e99f8e55a287a5e150031cefdb5c4c2d529b47f43aae0221b0aefce9a46fa90
4
- data.tar.gz: 86ea42d48978c8b96788232791b1e73438dfc4969a030f6b9eda575dc046fc8a
3
+ metadata.gz: d461854504d327c8e6b363d968b1aebe460d65918a470db73fcab94f9ec43205
4
+ data.tar.gz: ddd0ae3a98dc95174c0f0bdde89c968d3d45af995c65e42bc0e13f5b430466e2
5
5
  SHA512:
6
- metadata.gz: 149e7c2883d39ce168c74c1b2260e1f841dc15f892ff960a90b444e3e2ffaeb9a785a92c2cc78ba1996c12862f9f703658936e725d049383f6f7b03632cbacf2
7
- data.tar.gz: dc85d76c7dfa96f6dfbd80e75ce695caca2c82794ffefd4d68dd6f75644af97af73045babe00d5305fd222fa4f59c4fa420069d096d81fdc392b3c54a71acd59
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 `json` 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
 
@@ -247,10 +254,10 @@ hash.deep_transform_keys!(&:to_s)
247
254
  # => '{"a":{"b":"c","d":"e"},"f":"g"}'
248
255
 
249
256
  { f: 'g', a: { d: 'e', b: 'c' } }.to_struct
250
- # => #<OpenStruct f="g", a={:d=>"e", :b=>"c"}>
257
+ # => #<struct f="g", a={:d=>"e", :b=>"c"}>
251
258
 
252
259
  { f: 'g', a: { d: 'e', b: 'c' } }.to_deep_struct
253
- # => #<OpenStruct f="g", a=#<OpenStruct d="e", b="c">>
260
+ # => #<struct f="g", a=#<struct d="e", b="c">>
254
261
 
255
262
  { a: { b: 'c', d: 'e' }, f: 'g' }.to_dynamodb
256
263
  # => { :a => { :M => { :b => { :S => "c" }, :d => { :S => "e" } } }, :f => { :S => "g" } }
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
@@ -3,142 +3,13 @@
3
3
  require 'digest'
4
4
  require 'json'
5
5
  require 'time'
6
-
7
- class Array
8
- def to_dynamodb = { L: map(&:to_dynamodb) }
9
- end
10
-
11
- class Hash
12
- def deep_keys = map { |k,v| v.respond_to?(:deep_keys) ? [k] + v.deep_keys : k }.flatten
13
- def deep_sort = sort.map { |k,v| [ k, v.try(:deep_sort) { |x| x } ] }.to_h
14
- def deep_transform_keys(&block) = deep_transform(:transform_keys, &block)
15
- def deep_transform_keys!(&block) = deep_transform(:transform_keys!, &block)
16
- def encode64 = to_json.encode64
17
- def except(*keys) = reject { |key,_| keys.include? key }
18
- def strict_encode64 = to_json.strict_encode64
19
- def stringify_names = deep_transform_keys(&:to_s)
20
- def stringify_names! = deep_transform_keys!(&:to_s)
21
- def symbolize_names = deep_transform_keys(&:to_sym)
22
- def symbolize_names! = deep_transform_keys!(&:to_sym)
23
- def to_form = URI.encode_www_form(self)
24
- def to_json_sorted = deep_sort.to_json
25
- def to_struct = OpenStruct.new(self)
26
-
27
- ##
28
- # Adapted from ActiveSupport Hash#deep_merge
29
- # https://github.com/rails/rails/blob/f95c0b7e96eb36bc3efc0c5beffbb9e84ea664e4/activesupport/lib/active_support/core_ext/hash/deep_merge.rb
30
- def deep_merge(other, &block)
31
- merge(other) do |key, a, b|
32
- if a.is_a?(Hash) && b.is_a?(Hash)
33
- a.deep_merge(b, &block)
34
- elsif a.is_a?(Array) && b.is_a?(Array)
35
- a + b
36
- elsif block_given?
37
- yield key, a, b
38
- else
39
- b
40
- end
41
- end
42
- end
43
-
44
- def to_deep_struct
45
- to_struct.tap do |struct|
46
- struct.to_h.each do |key, val|
47
- struct[key] = if val.is_a?(Array)
48
- val.map do |item|
49
- item.respond_to?(:to_deep_struct) ? item.to_deep_struct : item
50
- end
51
- elsif val.is_a?(Hash)
52
- val.to_deep_struct
53
- else
54
- val
55
- end
56
- end
57
- end
58
- end
59
-
60
- def to_dynamodb
61
- map do |key, val|
62
- { key => val.is_a?(Hash) ? { M: val.to_dynamodb } : val.to_dynamodb }
63
- end.reduce(&:merge)
64
- end
65
-
66
- def to_h_from_dynamodb
67
- decode = -> (i) do
68
- type, val = i.first
69
- case type.to_sym
70
- when :S then val
71
- when :N then val =~ /^[0-9]+$/ ? val.to_i : val.to_f
72
- when :L then val.map(&decode)
73
- when :M then val.transform_values(&decode)
74
- end
75
- end
76
- map do |key, val|
77
- { key => decode === val }
78
- end.reduce(&:merge)
79
- end
80
-
81
- private
82
-
83
- def deep_transform(method, &block)
84
- f = -> (x) { x.respond_to?(:"deep_#{method}") ? x.send(:"deep_#{method}", &block) : x }
85
- block_given? ? send(method, &block).map do |key, val|
86
- [key, val.is_a?(Array) ? val.map(&f) : val.then(&f)]
87
- end.to_h : self
88
- end
89
- end
90
-
91
- class Numeric
92
- def to_dynamodb = { N: to_s }
93
- end
94
-
95
- class Integer
96
- def weeks = days * 7
97
- def days = hours * 24
98
- def hours = minutes * 60
99
- def minutes = seconds * 60
100
- def seconds = self
101
- def utc = UTC.at(self)
102
-
103
- alias :second :seconds
104
- alias :minute :minutes
105
- alias :hour :hours
106
- alias :day :days
107
- alias :week :weeks
108
- end
109
-
110
- class Object
111
- def try(method, *args, **kwargs, &block)
112
- send(method, *args, **kwargs)
113
- rescue
114
- block_given? ? yield(self) : nil
115
- end
116
- end
117
-
118
- class String
119
- def /(path) = File.join(self, path.to_s)
120
- def camel_case = split(/[_ ]/).map(&:capitalize).join
121
- def decode64 = self.unpack1('m')
122
- def encode64 = [self].pack('m')
123
- def md5sum = Digest::MD5.hexdigest(self)
124
- def sha1sum = Digest::SHA1.hexdigest(self)
125
- def snake_case = gsub(/([a-z])([A-Z])/, '\1_\2').gsub(/ /, '_').downcase
126
- def strict_decode64 = self.unpack1('m0')
127
- def strict_encode64 = [self].pack('m0')
128
- def to_dynamodb = { S: self }
129
- def to_h_from_json(...) = JSON.parse(self, ...)
130
- def to_h_from_form = URI.decode_www_form(self).to_h
131
- def utc = UTC.parse(self)
132
- end
133
-
134
- class Symbol
135
- def camel_case = to_s.camel_case.to_sym
136
- def snake_case = to_s.snake_case.to_sym
137
- def to_dynamodb = { S: to_s }
138
- end
139
-
140
- class UTC < Time
141
- def initialize(...) = super.utc
142
- def self.at(...) = super.utc
143
- def self.now = super.utc
144
- end
6
+ require 'uri'
7
+
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.0'
4
+ VERSION = '1.3.0'
5
5
  end
metadata CHANGED
@@ -1,28 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yake
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Mancevice
8
+ autorequire:
8
9
  bindir: bin
9
10
  cert_chain: []
10
- date: 2025-01-15 00:00:00.000000000 Z
11
+ date: 2026-06-21 00:00:00.000000000 Z
11
12
  dependencies:
12
- - !ruby/object:Gem::Dependency
13
- name: json
14
- requirement: !ruby/object:Gem::Requirement
15
- requirements:
16
- - - ">="
17
- - !ruby/object:Gem::Version
18
- version: '0'
19
- type: :runtime
20
- prerelease: false
21
- version_requirements: !ruby/object:Gem::Requirement
22
- requirements:
23
- - - ">="
24
- - !ruby/object:Gem::Version
25
- version: '0'
26
13
  - !ruby/object:Gem::Dependency
27
14
  name: logger
28
15
  requirement: !ruby/object:Gem::Requirement
@@ -37,6 +24,7 @@ dependencies:
37
24
  - - ">="
38
25
  - !ruby/object:Gem::Version
39
26
  version: '0'
27
+ description:
40
28
  email:
41
29
  - alexander.mancevice@hey.com
42
30
  executables: []
@@ -52,11 +40,21 @@ files:
52
40
  - lib/yake/errors.rb
53
41
  - lib/yake/logger.rb
54
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
55
51
  - lib/yake/version.rb
56
52
  homepage: https://github.com/amancevice/yake
57
53
  licenses:
58
54
  - MIT
59
- metadata: {}
55
+ metadata:
56
+ rubygems_mfa_required: 'true'
57
+ post_install_message:
60
58
  rdoc_options: []
61
59
  require_paths:
62
60
  - lib
@@ -71,7 +69,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
71
69
  - !ruby/object:Gem::Version
72
70
  version: '0'
73
71
  requirements: []
74
- rubygems_version: 3.6.2
72
+ rubygems_version: 3.5.22
73
+ signing_key:
75
74
  specification_version: 4
76
75
  summary: Rake-like DSL for declaring AWS Lambda function handlers
77
76
  test_files: []