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 +4 -4
- data/README.md +13 -6
- data/lib/yake/api.rb +13 -53
- data/lib/yake/datadog.rb +16 -13
- data/lib/yake/dsl.rb +11 -6
- data/lib/yake/errors.rb +22 -4
- data/lib/yake/logger.rb +10 -8
- data/lib/yake/support/array.rb +8 -0
- data/lib/yake/support/hash.rb +88 -0
- data/lib/yake/support/integer.rb +18 -0
- data/lib/yake/support/numeric.rb +7 -0
- data/lib/yake/support/object.rb +11 -0
- data/lib/yake/support/string.rb +19 -0
- data/lib/yake/support/symbol.rb +9 -0
- data/lib/yake/support/utc.rb +9 -0
- data/lib/yake/support.rb +8 -138
- data/lib/yake/version.rb +1 -1
- metadata +13 -18
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d461854504d327c8e6b363d968b1aebe460d65918a470db73fcab94f9ec43205
|
|
4
|
+
data.tar.gz: ddd0ae3a98dc95174c0f0bdde89c968d3d45af995c65e42bc0e13f5b430466e2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 43fbd717b48b43c49f555b6a6176bb64595a75df6c250b30b851a2a29a6cd0d8fe8808a156f9c7411de8777a6564b49b57197244761d080ae8a90632971a4097
|
|
7
|
+
data.tar.gz: 37a8a171dc9ce1bed8c31a97c990cb5576b8302bcec08445b48f6e20850059998bc6c7f6d02723addb9b90fc3ae708682dec440557c6494e3581fedd50857e93
|
data/README.md
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://rubygems.org/gems/yake)
|
|
4
4
|
[](https://github.com/amancevice/yake/actions/workflows/rspec.yml)
|
|
5
|
-
[](https://codeclimate.com/github/amancevice/yake/test_coverage)
|
|
6
|
-
[](https://codeclimate.com/github/amancevice/yake/maintainability)
|
|
7
5
|
|
|
8
6
|
[](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.
|
|
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
|
|
13
|
-
def route(event, context = nil
|
|
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 [#{
|
|
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 = ->
|
|
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
|
|
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
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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, &
|
|
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 = ->
|
|
42
|
-
log_return = ->
|
|
43
|
-
logger.info("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 '#{
|
|
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 '#{
|
|
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,
|
|
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,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,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
|
data/lib/yake/support.rb
CHANGED
|
@@ -5,141 +5,11 @@ require 'json'
|
|
|
5
5
|
require 'time'
|
|
6
6
|
require 'uri'
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
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.
|
|
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:
|
|
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.
|
|
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
|