meta-api 0.1.1 → 0.2.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.
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meta
4
+ module Utils
5
+ class Kwargs
6
+ class ArgumentConsumer
7
+ DEFAULT_TRANSFORMER = ->(value) { value }
8
+
9
+ def initialize(name:, normalizer: DEFAULT_TRANSFORMER, validator: nil, default: nil, alias_names: [])
10
+ @key_name = name
11
+ @consumer_names = [name] + alias_names
12
+ @default_proc = -> { default.dup } if default
13
+ @normalizer = normalizer
14
+ @validator = validator
15
+ end
16
+
17
+ def consume(final_args, args)
18
+ @consumer_names.each do |name|
19
+ return if consume_name(final_args, args, name)
20
+ end
21
+
22
+ if @default_proc
23
+ default_value = @default_proc.call
24
+ final_args[@key_name] = @normalizer.call(default_value)
25
+ end
26
+ end
27
+
28
+ def consume_name(final_args, args, consumer_name)
29
+ if args.key?(consumer_name)
30
+ value = @normalizer.call(args.delete(consumer_name))
31
+ @validator.call(value) if @validator
32
+ final_args[@key_name] = value
33
+ true
34
+ else
35
+ false
36
+ end
37
+ end
38
+ end
39
+
40
+ class ProcConsumer
41
+ def initialize(&blk)
42
+ @block = blk
43
+ end
44
+
45
+ def consume(final_args, args)
46
+ @block.call(final_args, args) if @block
47
+ end
48
+ end
49
+
50
+ class CompositeConsumer
51
+ def initialize(*consumers)
52
+ @consumers = consumers
53
+ end
54
+
55
+ def consume(final_args, args)
56
+ @consumers.each do |consumer|
57
+ consumer.consume(final_args, args)
58
+ end
59
+ end
60
+ end
61
+
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meta
4
+ module Utils
5
+ class Kwargs
6
+ module ExtrasConsumers
7
+ Ignore = ProcConsumer.new
8
+ Merged = ProcConsumer.new do |final_args, args|
9
+ final_args.merge!(args)
10
+ end
11
+ RaiseError = ProcConsumer.new do |final_args, args|
12
+ extras_keys = args.keys
13
+ raise ArgumentError, "不接受额外的关键字参数:#{extras_keys.join(', ')}" unless extras_keys.empty?
14
+ end
15
+
16
+ def self.resolve_handle_extras(sym)
17
+ return nil if sym.nil?
18
+
19
+ case sym
20
+ when :ignore
21
+ ExtrasConsumers::Ignore
22
+ when :merged
23
+ ExtrasConsumers::Merged
24
+ when :raise_error
25
+ ExtrasConsumers::RaiseError
26
+ else
27
+ raise ArgumentError, "handle_extras 只接受 :ignore, :merged, :raise_error 三种值,当前传递:#{sym}"
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meta
4
+ module Utils
5
+ class Kwargs
6
+ module Helpers
7
+ class << self
8
+ # 将 options 内的值修正为固定值,该方法会原地修改 options 选项。
9
+ # 如果 options 中的缺失相应的值,则使用 fixed_values 中的值补充;如果 options 中的值不等于 fixed_values 中对应的值,则抛出异常。
10
+ # 示例:
11
+ # (1)fix!({}, { a: 1, b: 2 }) # => { a: 1, b: 2 }
12
+ # (2)fix!({ a: 1 }, { a: 2 }) # raise error
13
+ def fix!(options, fixed_values)
14
+ fixed_values.each do |key, value|
15
+ if options.include?(key)
16
+ if options[key] != value
17
+ raise ArgumentError, "关键字参数 #{key} 的值不正确,必须为 #{value}"
18
+ end
19
+ else
20
+ options[key] = value
21
+ end
22
+ end
23
+ options
24
+ end
25
+
26
+ def merge_defaults!(options, defaults)
27
+ defaults.each do |key, value|
28
+ options[key] = value unless options[key]
29
+ end
30
+ options
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
data/meta-api.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "meta-api"
3
- spec.version = "0.1.1"
3
+ spec.version = "0.2.0"
4
4
  spec.authors = ["yetrun"]
5
5
  spec.email = ["yetrun@foxmail.com"]
6
6
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: meta-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - yetrun
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-06-01 00:00:00.000000000 Z
11
+ date: 2024-06-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hash_to_struct
@@ -81,10 +81,14 @@ files:
81
81
  - lib//meta/route_dsl/parameters_builder.rb
82
82
  - lib//meta/route_dsl/route_builder.rb
83
83
  - lib//meta/route_dsl/uniformed_params_builder.rb
84
+ - lib//meta/scope/base.rb
85
+ - lib//meta/scope/utils.rb
84
86
  - lib//meta/swagger_doc.rb
85
87
  - lib//meta/utils/kwargs/builder.rb
86
- - lib//meta/utils/kwargs/check.rb
87
88
  - lib//meta/utils/kwargs/checker.rb
89
+ - lib//meta/utils/kwargs/consumers.rb
90
+ - lib//meta/utils/kwargs/extras_consumers.rb
91
+ - lib//meta/utils/kwargs/helpers.rb
88
92
  - lib//meta/utils/path.rb
89
93
  - lib//meta/utils/route_dsl_builders.rb
90
94
  - meta-api.gemspec
@@ -1,91 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # 运行时检查关键字参数。(已过时,请使用 Builder)
4
- #
5
- # 在 Ruby 3 中,关键字参数有所变化。简单来说,关键字参数和 Hash 类型不再自动转化,并且一般情况下推荐使用关键字参数。
6
- # 但关键字参数还是有稍稍不足之处,比如在做一些复杂的关键字参数定义时。
7
- #
8
- # 这个文件编写了一个方法,帮助我们在运行时检查关键字参数。这样,我们就可以像下面这样笼统的方式定义参数,不必用明确的关
9
- # 键字参数名称。
10
- #
11
- # def method_name(x, y, z, **kwargs); end
12
- # def method_name(x, y, z, kwargs={}); end
13
- #
14
- # 使用示例:
15
- #
16
- # # 返回 { x: 1, y: 2, z: 3 }
17
- # Meta::Utils::KeywordArgs.check(args: { x: 1, y: 2 }, schema: [:x, :y, { z: 3 }])
18
- #
19
- # # 返回 { x: 1, y: 2, z: 4 }
20
- # Meta::Utils::KeywordArgs.check(args: { x: 1, y: 2, z: 4 }, schema: [:x, :y, { z: 3 }])
21
- #
22
- # # Error: `x` is required
23
- # Meta::Utils::KeywordArgs.check(args: { y: 2, z: 3 }, schema: [:x, :y, { z: 3 }])
24
- #
25
- # # Error: `a` is not allowed
26
- # Meta::Utils::KeywordArgs.check(args: { a: 1, y: 2, z: 3 }, schema: [:x, :y, { z: 3 }])
27
-
28
- module Meta
29
- module Utils
30
- class KeywordArgs
31
- class << self
32
- def check(args:, schema:)
33
- schemas = build_schemas(schema)
34
-
35
- # 不接受额外的关键字参数
36
- extras = args.keys - schemas.keys
37
- raise "不接受额外的关键字参数:#{extras.join(', ')}" unless extras.empty?
38
-
39
- # 通过 schema 导出关键字参数
40
- missing = []
41
- result = schemas.map do |name, spec|
42
- if args.include?(name)
43
- [name, args[name]]
44
- elsif spec.include?(:default)
45
- [name, spec[:default]]
46
- else
47
- missing << name
48
- end
49
- end.to_h
50
-
51
- # 检查以上导出过程中是否找到缺失的参数
52
- if missing.empty?
53
- result
54
- else
55
- raise "缺失必要的关键字参数:#{missing.join(', ')}"
56
- end
57
- end
58
-
59
- private
60
-
61
- def build_schemas(spec)
62
- if spec.is_a?(Array)
63
- build_schemas_from_array(spec)
64
- elsif spec.is_a?(Hash)
65
- build_schemas_from_hash(spec)
66
- elsif spec.is_a?(Symbol)
67
- build_schemas_from_symbol(spec)
68
- else
69
- raise "未知的参数类型:#{spec.class}"
70
- end
71
- end
72
-
73
- def build_schemas_from_array(spec_array)
74
- spec_array.inject({}) do |accumulated, val|
75
- accumulated.merge!(build_schemas(val))
76
- end
77
- end
78
-
79
- def build_schemas_from_hash(spec_hash)
80
- spec_hash.transform_values do |val|
81
- { default: val }
82
- end
83
- end
84
-
85
- def build_schemas_from_symbol(spec_symbol)
86
- { spec_symbol => {} }
87
- end
88
- end
89
- end
90
- end
91
- end