pakyow-support 0.11.3 → 1.0.0.rc1
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 +5 -5
- data/{pakyow-support/CHANGELOG.md → CHANGELOG.md} +4 -0
- data/LICENSE +4 -0
- data/{pakyow-support/README.md → README.md} +1 -2
- data/lib/pakyow/support/aargv.rb +25 -0
- data/lib/pakyow/support/bindable.rb +19 -0
- data/lib/pakyow/support/class_state.rb +49 -0
- data/lib/pakyow/support/cli/runner.rb +106 -0
- data/lib/pakyow/support/cli/style.rb +13 -0
- data/lib/pakyow/support/configurable/config.rb +153 -0
- data/lib/pakyow/support/configurable/setting.rb +52 -0
- data/lib/pakyow/support/configurable.rb +103 -0
- data/lib/pakyow/support/core_refinements/array/ensurable.rb +25 -0
- data/lib/pakyow/support/core_refinements/method/introspection.rb +21 -0
- data/lib/pakyow/support/core_refinements/proc/introspection.rb +21 -0
- data/lib/pakyow/support/core_refinements/string/normalization.rb +50 -0
- data/lib/pakyow/support/deep_dup.rb +61 -0
- data/lib/pakyow/support/deep_freeze.rb +82 -0
- data/lib/pakyow/support/definable.rb +242 -0
- data/lib/pakyow/support/dependencies.rb +61 -0
- data/lib/pakyow/support/extension.rb +82 -0
- data/lib/pakyow/support/hookable.rb +227 -0
- data/lib/pakyow/support/indifferentize.rb +183 -0
- data/lib/pakyow/support/inflector.rb +13 -0
- data/lib/pakyow/support/inspectable.rb +88 -0
- data/lib/pakyow/support/logging.rb +31 -0
- data/lib/pakyow/support/makeable/object_maker.rb +30 -0
- data/lib/pakyow/support/makeable/object_name.rb +45 -0
- data/lib/pakyow/support/makeable/object_namespace.rb +28 -0
- data/lib/pakyow/support/makeable.rb +117 -0
- data/lib/pakyow/support/message_verifier.rb +74 -0
- data/lib/pakyow/support/path_version.rb +21 -0
- data/lib/pakyow/support/pipeline/object.rb +41 -0
- data/lib/pakyow/support/pipeline.rb +335 -0
- data/lib/pakyow/support/safe_string.rb +60 -0
- data/lib/pakyow/support/serializer.rb +49 -0
- data/lib/pakyow/support/silenceable.rb +21 -0
- data/lib/pakyow/support/string_builder.rb +62 -0
- data/lib/pakyow/support.rb +1 -0
- metadata +107 -26
- data/pakyow-support/LICENSE +0 -20
- data/pakyow-support/lib/pakyow/support/aargv.rb +0 -15
- data/pakyow-support/lib/pakyow/support/array.rb +0 -9
- data/pakyow-support/lib/pakyow/support/dir.rb +0 -32
- data/pakyow-support/lib/pakyow/support/dup.rb +0 -23
- data/pakyow-support/lib/pakyow/support/file.rb +0 -5
- data/pakyow-support/lib/pakyow/support/hash.rb +0 -47
- data/pakyow-support/lib/pakyow/support/kernel.rb +0 -9
- data/pakyow-support/lib/pakyow/support/string.rb +0 -36
- data/pakyow-support/lib/pakyow/support.rb +0 -8
- data/pakyow-support/lib/pakyow-support.rb +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7f55f83e04891fdd69aaafe9d59ab21d250cd6fcdc37aa2fbfcb0a8eaad576be
|
4
|
+
data.tar.gz: 980a9b0005d1f5432b995974c3065c4ab2a9484d7ad42c0d7cb2f4b10a3e655d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6563a073ab30d40996accbae5e9aa5f8f4dcd6adb3a63b02dc38ffbd51a604aaccc0608d82edc7dd74571fd7b6c44b580c29c70dffc1171249cecabf9f9936f6
|
7
|
+
data.tar.gz: 30c696d99b2afa619298d7ea5bac825442f9578ed738c3180d4973f94058d0bf6033b3341cc5a476da2ec65071ddda0436b39bd40c32d2440d6c17649aa9de36
|
data/LICENSE
ADDED
@@ -16,8 +16,7 @@ Source code can be downloaded as part of the Pakyow project on Github:
|
|
16
16
|
|
17
17
|
# License
|
18
18
|
|
19
|
-
Pakyow Support is
|
20
|
-
License](http://opensource.org/licenses/MIT).
|
19
|
+
Pakyow Support is free and open-source under the [LGPLv3 license](https://choosealicense.com/licenses/lgpl-3.0/).
|
21
20
|
|
22
21
|
# Support
|
23
22
|
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pakyow/support/core_refinements/array/ensurable"
|
4
|
+
|
5
|
+
module Pakyow
|
6
|
+
module Support
|
7
|
+
class Aargv
|
8
|
+
using Refinements::Array::Ensurable
|
9
|
+
|
10
|
+
def self.normalize(args, opts)
|
11
|
+
Hash[opts.map { |opt_name, opt_types|
|
12
|
+
[opt_name, value_of_type(args, Array.ensure(opt_types))]
|
13
|
+
}.reject { |pair| pair[1].nil? }]
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.value_of_type(values, types)
|
17
|
+
if match = values.find { |value| types.find { |type| value.is_a?(type) } }
|
18
|
+
values.delete(match)
|
19
|
+
else
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Pakyow
|
4
|
+
module Support
|
5
|
+
# Makes an object bindable.
|
6
|
+
#
|
7
|
+
module Bindable
|
8
|
+
def include?(key)
|
9
|
+
respond_to?(key.to_s.to_sym)
|
10
|
+
end
|
11
|
+
|
12
|
+
def [](key)
|
13
|
+
if include?(key)
|
14
|
+
public_send(key.to_s.to_sym)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pakyow/support/deep_dup"
|
4
|
+
|
5
|
+
module Pakyow
|
6
|
+
module Support
|
7
|
+
module ClassState
|
8
|
+
using DeepDup
|
9
|
+
|
10
|
+
def class_state(name, default: nil, inheritable: false, getter: true)
|
11
|
+
ivar = :"@#{name}"
|
12
|
+
@__class_state[ivar] = {
|
13
|
+
default: default,
|
14
|
+
inheritable: inheritable
|
15
|
+
}
|
16
|
+
|
17
|
+
instance_variable_set(ivar, default.deep_dup)
|
18
|
+
|
19
|
+
if getter
|
20
|
+
define_singleton_method name do
|
21
|
+
instance_variable_get(ivar)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.extended(base)
|
27
|
+
unless base.instance_variable_defined?(:@__class_state)
|
28
|
+
base.instance_variable_set(:@__class_state, {})
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def inherited(subclass)
|
33
|
+
subclass.instance_variable_set(:@__class_state, @__class_state.deep_dup)
|
34
|
+
|
35
|
+
@__class_state.each do |ivar, options|
|
36
|
+
if options[:inheritable]
|
37
|
+
subclass.instance_variable_set(ivar, instance_variable_get(ivar).deep_dup)
|
38
|
+
elsif @__class_state[ivar][:default]
|
39
|
+
subclass.instance_variable_set(ivar, @__class_state[ivar][:default].deep_dup)
|
40
|
+
else
|
41
|
+
subclass.instance_variable_set(ivar, nil)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
super
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "tty-command"
|
4
|
+
require "tty-spinner"
|
5
|
+
|
6
|
+
require "pakyow/support/cli/style"
|
7
|
+
|
8
|
+
module Pakyow
|
9
|
+
module Support
|
10
|
+
# Runs a command, or block of code, with consistent command-line messaging.
|
11
|
+
#
|
12
|
+
module CLI
|
13
|
+
class Runner
|
14
|
+
SPINNER = :dots
|
15
|
+
FAILURE_MARK = "✕"
|
16
|
+
SUCCESS_MARK = "✓"
|
17
|
+
FAILURE_MESSAGE = "failed"
|
18
|
+
SUCCESS_MESSAGE = ""
|
19
|
+
|
20
|
+
def initialize(message:)
|
21
|
+
@spinner = TTY::Spinner.new(
|
22
|
+
Support::CLI.style.bold(":spinner #{message}"),
|
23
|
+
format: SPINNER,
|
24
|
+
success_mark: SUCCESS_MARK,
|
25
|
+
error_mark: FAILURE_MARK
|
26
|
+
)
|
27
|
+
|
28
|
+
@succeeded = @failed = false
|
29
|
+
end
|
30
|
+
|
31
|
+
# Runs a command or block of code. If a value for `command` is passed with
|
32
|
+
# the block, the result will be yielded to the block on success.
|
33
|
+
#
|
34
|
+
def run(*command)
|
35
|
+
@spinner.auto_spin
|
36
|
+
|
37
|
+
if command.empty? && block_given?
|
38
|
+
yield self
|
39
|
+
succeeded
|
40
|
+
else
|
41
|
+
result = TTY::Command.new(printer: :null, pty: true).run!(*command)
|
42
|
+
|
43
|
+
if result.failure?
|
44
|
+
failed(result.err)
|
45
|
+
else
|
46
|
+
succeeded
|
47
|
+
|
48
|
+
if block_given?
|
49
|
+
yield result
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Called when the command succeeds.
|
56
|
+
#
|
57
|
+
def succeeded(output = "")
|
58
|
+
unless completed?
|
59
|
+
@succeeded = true
|
60
|
+
@spinner.success(Support::CLI.style.green(SUCCESS_MESSAGE))
|
61
|
+
puts indent_output(output) unless output.empty?
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Called when the command fails.
|
66
|
+
#
|
67
|
+
def failed(output = "")
|
68
|
+
unless completed?
|
69
|
+
@failed = true
|
70
|
+
@spinner.error(Support::CLI.style.red(FAILURE_MESSAGE))
|
71
|
+
puts indent_output(output) unless output.empty?
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Returns `true` if the command has completed.
|
76
|
+
#
|
77
|
+
def completed?
|
78
|
+
succeeded? || failed?
|
79
|
+
end
|
80
|
+
|
81
|
+
# Returns `true` if the command has completed successfully.
|
82
|
+
#
|
83
|
+
def succeeded?
|
84
|
+
@succeeded == true
|
85
|
+
end
|
86
|
+
|
87
|
+
# Returns `true` if the command has completed unsuccessfully.
|
88
|
+
#
|
89
|
+
def failed?
|
90
|
+
@failed == true
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
ANSI_REGEX = /\x1B\[[0-9;]*[a-zA-Z]/
|
96
|
+
|
97
|
+
def indent_output(output)
|
98
|
+
output.split("\n").map { |line|
|
99
|
+
first_real_string = line.split(ANSI_REGEX).reject(&:empty?).first
|
100
|
+
line.sub(first_real_string.to_s, " #{first_real_string}")
|
101
|
+
}.join("\n")
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "concurrent/hash"
|
4
|
+
|
5
|
+
require "pakyow/support/deep_dup"
|
6
|
+
require "pakyow/support/deep_freeze"
|
7
|
+
|
8
|
+
require "pakyow/support/configurable/setting"
|
9
|
+
|
10
|
+
module Pakyow
|
11
|
+
module Support
|
12
|
+
module Configurable
|
13
|
+
# @api private
|
14
|
+
class Config
|
15
|
+
using DeepDup
|
16
|
+
|
17
|
+
extend DeepFreeze
|
18
|
+
unfreezable :configurable
|
19
|
+
|
20
|
+
# @api private
|
21
|
+
attr_reader :__settings, :__defaults, :__groups
|
22
|
+
|
23
|
+
def initialize(configurable)
|
24
|
+
@configurable = configurable
|
25
|
+
|
26
|
+
@__settings = Concurrent::Hash.new
|
27
|
+
@__defaults = Concurrent::Hash.new
|
28
|
+
@__groups = Concurrent::Hash.new
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize_copy(_)
|
32
|
+
@__defaults = @__defaults.deep_dup
|
33
|
+
@__settings = @__settings.deep_dup
|
34
|
+
@__groups = @__groups.deep_dup
|
35
|
+
|
36
|
+
@__settings.each do |key, _|
|
37
|
+
define_setting_methods(key)
|
38
|
+
end
|
39
|
+
|
40
|
+
@__groups.each do |key, _|
|
41
|
+
define_group_methods(key)
|
42
|
+
end
|
43
|
+
|
44
|
+
super
|
45
|
+
end
|
46
|
+
|
47
|
+
def setting(name, default = default_omitted = true, &block)
|
48
|
+
tap do
|
49
|
+
name = name.to_sym
|
50
|
+
default = nil if default_omitted
|
51
|
+
|
52
|
+
unless @__settings.include?(name)
|
53
|
+
define_setting_methods(name)
|
54
|
+
end
|
55
|
+
|
56
|
+
@__settings[name] = Setting.new(default: default, configurable: @configurable, &block)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def defaults(environment, &block)
|
61
|
+
@__defaults[environment] = block
|
62
|
+
end
|
63
|
+
|
64
|
+
def configurable(group, &block)
|
65
|
+
group = group.to_sym
|
66
|
+
config = Config.new(@configurable)
|
67
|
+
config.instance_eval(&block)
|
68
|
+
|
69
|
+
unless @__groups.include?(group)
|
70
|
+
define_group_methods(group)
|
71
|
+
end
|
72
|
+
|
73
|
+
@__groups[group] = config
|
74
|
+
end
|
75
|
+
|
76
|
+
def configure_defaults!(configured_environment)
|
77
|
+
if defaults = @__defaults[configured_environment.to_s.to_sym]
|
78
|
+
instance_eval(&defaults)
|
79
|
+
end
|
80
|
+
|
81
|
+
@__groups.values.each do |group|
|
82
|
+
group.configure_defaults!(configured_environment)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def update_configurable(configurable)
|
87
|
+
@configurable = configurable
|
88
|
+
|
89
|
+
@__settings.values.each do |setting|
|
90
|
+
setting.update_configurable(configurable)
|
91
|
+
end
|
92
|
+
|
93
|
+
@__groups.values.each do |group|
|
94
|
+
group.update_configurable(configurable)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def to_h
|
99
|
+
hash = {}
|
100
|
+
|
101
|
+
@__settings.each_with_object(hash) { |(name, setting), h|
|
102
|
+
h[name] = setting.value
|
103
|
+
}
|
104
|
+
|
105
|
+
@__groups.each_with_object(hash) { |(name, group), h|
|
106
|
+
h[name] = group.to_h
|
107
|
+
}
|
108
|
+
|
109
|
+
hash
|
110
|
+
end
|
111
|
+
|
112
|
+
def eval(setting, context)
|
113
|
+
value = public_send(setting)
|
114
|
+
if value.is_a?(Proc)
|
115
|
+
context.instance_eval(&value)
|
116
|
+
else
|
117
|
+
value
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
private
|
122
|
+
|
123
|
+
def find_setting(name)
|
124
|
+
@__settings[name.to_sym]
|
125
|
+
end
|
126
|
+
|
127
|
+
def find_group(name)
|
128
|
+
@__groups[name.to_sym]
|
129
|
+
end
|
130
|
+
|
131
|
+
def define_setting_methods(name)
|
132
|
+
singleton_class.define_method name do |&block|
|
133
|
+
if block
|
134
|
+
find_setting(name).set(block)
|
135
|
+
else
|
136
|
+
find_setting(name).value
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
singleton_class.define_method :"#{name}=" do |value|
|
141
|
+
find_setting(name).set(value)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def define_group_methods(name)
|
146
|
+
singleton_class.define_method name do
|
147
|
+
find_group(name)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pakyow/support/deep_dup"
|
4
|
+
require "pakyow/support/deep_freeze"
|
5
|
+
|
6
|
+
module Pakyow
|
7
|
+
module Support
|
8
|
+
module Configurable
|
9
|
+
# @api private
|
10
|
+
class Setting
|
11
|
+
using DeepDup
|
12
|
+
|
13
|
+
extend DeepFreeze
|
14
|
+
unfreezable :configurable, :value
|
15
|
+
|
16
|
+
def initialize(default:, configurable:, &block)
|
17
|
+
@default, @block, @configurable = default, block, configurable
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize_copy(_)
|
21
|
+
@default = @default.deep_dup
|
22
|
+
super
|
23
|
+
end
|
24
|
+
|
25
|
+
def freeze
|
26
|
+
value
|
27
|
+
super
|
28
|
+
end
|
29
|
+
|
30
|
+
def set(value)
|
31
|
+
@value = value
|
32
|
+
end
|
33
|
+
|
34
|
+
def value
|
35
|
+
if instance_variable_defined?(:@value)
|
36
|
+
@value
|
37
|
+
else
|
38
|
+
@value = if @block
|
39
|
+
@configurable.instance_eval(&@block)
|
40
|
+
else
|
41
|
+
@default
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def update_configurable(configurable)
|
47
|
+
@configurable = configurable
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "concurrent/hash"
|
4
|
+
|
5
|
+
require "pakyow/support/class_state"
|
6
|
+
|
7
|
+
require "pakyow/support/configurable/config"
|
8
|
+
|
9
|
+
module Pakyow
|
10
|
+
module Support
|
11
|
+
# Makes an object configurable.
|
12
|
+
#
|
13
|
+
# class ConfigurableObject
|
14
|
+
# include Configurable
|
15
|
+
#
|
16
|
+
# setting :foo, "default"
|
17
|
+
# setting :bar
|
18
|
+
#
|
19
|
+
# defaults :development do
|
20
|
+
# setting :bar, "bar"
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# class ConfigurableSubclass < ConfigurableObject
|
25
|
+
# configure :development do
|
26
|
+
# config.foo = "development"
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# configure :production do
|
30
|
+
# config.foo = "production"
|
31
|
+
# end
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# instance = ConfigurableSubclass.new
|
35
|
+
# instance.configure! :development
|
36
|
+
#
|
37
|
+
# instance.config.foo
|
38
|
+
# # => "development"
|
39
|
+
# instance.config.bar
|
40
|
+
# # => "bar"
|
41
|
+
#
|
42
|
+
module Configurable
|
43
|
+
# @api private
|
44
|
+
def self.included(base)
|
45
|
+
base.extend ClassState
|
46
|
+
base.class_state :__config, default: Config.new(base), inheritable: true
|
47
|
+
base.class_state :__config_environments, default: Concurrent::Hash.new, inheritable: true
|
48
|
+
|
49
|
+
base.prepend Initializer
|
50
|
+
base.include CommonMethods
|
51
|
+
base.extend ClassMethods, CommonMethods
|
52
|
+
end
|
53
|
+
|
54
|
+
private def __config_environments
|
55
|
+
self.class.__config_environments
|
56
|
+
end
|
57
|
+
|
58
|
+
module Initializer
|
59
|
+
# @api private
|
60
|
+
def initialize(*)
|
61
|
+
@__config = self.class.__config.dup
|
62
|
+
@__config.update_configurable(self)
|
63
|
+
super
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
module ClassMethods
|
68
|
+
# Define configuration to be applied when configuring for an environment.
|
69
|
+
#
|
70
|
+
def configure(environment = :__global, &block)
|
71
|
+
@__config_environments[environment] = block
|
72
|
+
end
|
73
|
+
|
74
|
+
# @api private
|
75
|
+
def inherited(subclass)
|
76
|
+
super
|
77
|
+
subclass.config.update_configurable(subclass)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
module CommonMethods
|
82
|
+
extend Forwardable
|
83
|
+
def_delegators :@__config, :setting, :defaults, :configurable
|
84
|
+
|
85
|
+
def config
|
86
|
+
@__config
|
87
|
+
end
|
88
|
+
|
89
|
+
# Configures the object for an environment.
|
90
|
+
#
|
91
|
+
def configure!(configured_environment = nil)
|
92
|
+
@__config.configure_defaults!(configured_environment)
|
93
|
+
|
94
|
+
[:__global, configured_environment].compact.map(&:to_sym).select { |environment|
|
95
|
+
__config_environments.key?(environment)
|
96
|
+
}.each do |environment|
|
97
|
+
instance_eval(&__config_environments[environment])
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Pakyow
|
4
|
+
module Support
|
5
|
+
module Refinements
|
6
|
+
module Array
|
7
|
+
module Ensurable
|
8
|
+
refine ::Array.singleton_class do
|
9
|
+
# Ensures that +object+ is an array, converting it if necessary. This
|
10
|
+
# was added to safely wrap hashes, because +Array(hash)+ converts
|
11
|
+
# into an array of key/value pairs.
|
12
|
+
#
|
13
|
+
def ensure(object)
|
14
|
+
if object.respond_to?(:to_ary)
|
15
|
+
object.to_ary
|
16
|
+
else
|
17
|
+
[object]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Pakyow
|
4
|
+
module Support
|
5
|
+
module Refinements
|
6
|
+
module Method
|
7
|
+
module Introspection
|
8
|
+
refine ::Method do
|
9
|
+
# Returns true if +argument_name+ is defined as a keyword argument.
|
10
|
+
#
|
11
|
+
def keyword_argument?(argument_name)
|
12
|
+
parameters.any? { |(parameter_type, parameter_name)|
|
13
|
+
(parameter_type == :key || parameter_type == :keyreq) && parameter_name == argument_name
|
14
|
+
}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Pakyow
|
4
|
+
module Support
|
5
|
+
module Refinements
|
6
|
+
module Proc
|
7
|
+
module Introspection
|
8
|
+
refine ::Proc do
|
9
|
+
# Returns true if +argument_name+ is defined as a keyword argument.
|
10
|
+
#
|
11
|
+
def keyword_argument?(argument_name)
|
12
|
+
parameters.any? { |(parameter_type, parameter_name)|
|
13
|
+
(parameter_type == :key || parameter_type == :keyreq) && parameter_name == argument_name
|
14
|
+
}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Pakyow
|
4
|
+
module Support
|
5
|
+
module Refinements
|
6
|
+
module String
|
7
|
+
module Normalization
|
8
|
+
refine ::String.singleton_class do
|
9
|
+
# Normalizes a string into a predictable path.
|
10
|
+
#
|
11
|
+
# String.normalize_path("foo//bar/")
|
12
|
+
# # => "/foo/bar"
|
13
|
+
#
|
14
|
+
def normalize_path(path)
|
15
|
+
path = path.to_s
|
16
|
+
|
17
|
+
unless path.start_with?("/")
|
18
|
+
path = "/#{path}"
|
19
|
+
end
|
20
|
+
|
21
|
+
if path.include?("//")
|
22
|
+
path = path.to_s.gsub("//", "/")
|
23
|
+
end
|
24
|
+
|
25
|
+
unless path == "/"
|
26
|
+
path = path.chomp("/")
|
27
|
+
end
|
28
|
+
|
29
|
+
path
|
30
|
+
end
|
31
|
+
|
32
|
+
# Collapses a string into a version without tokens.
|
33
|
+
#
|
34
|
+
# String.collapse_path("/foo/:bar/baz")
|
35
|
+
# # => "/foo/baz"
|
36
|
+
def collapse_path(path)
|
37
|
+
if path == "/"
|
38
|
+
return path
|
39
|
+
end
|
40
|
+
|
41
|
+
path.to_s.split("/").keep_if { |part|
|
42
|
+
part[0] != ":"
|
43
|
+
}.join("/")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|