diva 0.3.2 → 1.0.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: 68d766412779aaedc71ea2ab874be3861238afff5b896d4d4bdab9e50e2c5103
4
- data.tar.gz: 7ca9cc8bec5f1b284fe51b078501831572519263feab02619b641ee7498543bd
3
+ metadata.gz: 65b2025d22ea687dfa98ca063ca511630ce75a4928e0e6be9581f7b6f2216ce2
4
+ data.tar.gz: 6b514157b95438022b2b28ab72b0af436489e3f8edf8e8c12bca80e1298a1b69
5
5
  SHA512:
6
- metadata.gz: 77ca8065a2a25a922bebdf0fe297242363f17e4277f411f4f72ece8ed0b61e26893452c6683d7815a55c96e5944f58e86436d77d38952fc9bf30c97c24e2c815
7
- data.tar.gz: 77627879b34087e1a4877125c54c489b0b799d768fee187bffff8f237e337cce67981ccae60eaa7481b964bbe841fd02bbed68740ab5f972f60c7aa7b7ac6517
6
+ metadata.gz: ea64c7762bc79c8c4eba0f9ac41fd3622a3af663c2a9f2057175695da9ba0f9226b4dbb71133e91c288dfc2799cdfae6d075fb84dab1905cc19ec2b7081b7045
7
+ data.tar.gz: af41fb3db4368b08f71af3cc1886ae44553865d4797f6402278ec1a6a812e2095e94ec752785734592c09f757f58fcde3198e185efc49a494260692dd2afb45f
@@ -18,11 +18,11 @@ Gem::Specification.new do |spec|
18
18
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_development_dependency "bundler", "~> 1.12"
22
- spec.add_development_dependency "rake", "~> 10.0"
23
- spec.add_development_dependency "minitest", "~> 5.0"
24
- spec.add_development_dependency "pry"
25
- spec.add_development_dependency "simplecov"
21
+ spec.add_development_dependency "bundler", '>= 1.16.1', '< 2.1'
22
+ spec.add_development_dependency "rake", '>= 12.3.2', '< 13.0'
23
+ spec.add_development_dependency "minitest", '>= 5.11.3', '< 5.12'
24
+ spec.add_development_dependency "pry", '>= 0.12.2', '< 1.0'
25
+ spec.add_development_dependency "simplecov", '>= 0.16.1', '< 1.0'
26
26
 
27
- spec.add_dependency "addressable", ">= 2.5", "< 2.6"
27
+ spec.add_dependency "addressable", ">= 2.5.2", "< 2.7"
28
28
  end
@@ -27,6 +27,13 @@ module Diva
27
27
  required
28
28
  end
29
29
 
30
+ def schema
31
+ {
32
+ name: @name.to_s,
33
+ constraint: @type.schema
34
+ }
35
+ end
36
+
30
37
  def to_sym
31
38
  name
32
39
  end
@@ -3,7 +3,6 @@
3
3
  いろんなリソースの基底クラス
4
4
  =end
5
5
 
6
- require 'diva/combinator'
7
6
  require 'diva/model_extend'
8
7
  require 'diva/uri'
9
8
  require 'diva/spec'
@@ -12,7 +11,6 @@ require 'securerandom'
12
11
 
13
12
  class Diva::Model
14
13
  include Comparable
15
- include Diva::Combinable
16
14
  extend Diva::ModelExtend
17
15
 
18
16
  def initialize(args)
@@ -145,6 +143,16 @@ class Diva::Model
145
143
  end
146
144
  end
147
145
 
146
+ def dig(key, *args)
147
+ return nil unless key.respond_to?(:to_sym)
148
+ value = fetch(key)
149
+ if value.nil? || args.empty?
150
+ value
151
+ else
152
+ value.dig(*args)
153
+ end
154
+ end
155
+
148
156
  private
149
157
  # URIがデフォルトで使うpath要素
150
158
  def path
@@ -57,6 +57,17 @@ module Diva::ModelExtend
57
57
  alias :keys :fields
58
58
  deprecate :keys, "fields", 2018, 02
59
59
 
60
+ def schema
61
+ {
62
+ fields: fields.map(&:schema),
63
+ uri: uri
64
+ }
65
+ end
66
+
67
+ def uri
68
+ @uri ||= Diva::URI("diva://object.type/#{slug || SecureRandom.uuid}")
69
+ end
70
+
60
71
  #
61
72
  # プライベートクラスメソッド
62
73
  #
@@ -28,6 +28,7 @@ Diva::Modelのサブクラスであれば、それを制約とすることがで
28
28
 
29
29
  =end
30
30
  require "time"
31
+ require 'diva/uri'
31
32
 
32
33
  module Diva::Type
33
34
  extend self
@@ -41,14 +42,18 @@ module Diva::Type
41
42
  end
42
43
 
43
44
  def optional(type)
44
- OptionalType.new(type)
45
+ UnionType.new(NULL, type)
46
+ end
47
+
48
+ def union(*types)
49
+ UnionType.new(*types)
45
50
  end
46
51
 
47
52
  # 全てのType共通のスーパークラス
48
53
  class MetaType
49
54
  attr_reader :name
50
55
 
51
- def initialize(name, *rest, &cast)
56
+ def initialize(name, *, &cast)
52
57
  @name = name.to_sym
53
58
  if cast
54
59
  define_singleton_method :cast, &cast
@@ -73,9 +78,26 @@ module Diva::Type
73
78
  end
74
79
 
75
80
  class AtomicType < MetaType
81
+ def initialize(name, recommended_class, *rest, &cast)
82
+ super(name, *rest, &cast)
83
+ @recommended_classes = Array(recommended_class)
84
+ end
85
+
86
+ def recommendation_point(value)
87
+ _, point = @recommended_classes.map.with_index{|k, i| [k, i] }.find{|k, _| value.is_a?(k) }
88
+ point
89
+ end
90
+
91
+ def schema
92
+ @schema ||= {type: uri}.freeze
93
+ end
94
+
95
+ def uri
96
+ @uri ||= Diva::URI("diva://atomic.type/#{name}")
97
+ end
76
98
  end
77
99
 
78
- INT = AtomicType.new(:int) do |v|
100
+ INT = AtomicType.new(:int, [Integer]) do |v|
79
101
  case v
80
102
  when Integer
81
103
  v
@@ -89,7 +111,7 @@ module Diva::Type
89
111
  raise Diva::InvalidTypeError, "The value is not a `#{name}'."
90
112
  end
91
113
  end
92
- FLOAT = AtomicType.new(:float) do |v|
114
+ FLOAT = AtomicType.new(:float, [Float]) do |v|
93
115
  case v
94
116
  when Float
95
117
  v
@@ -99,7 +121,7 @@ module Diva::Type
99
121
  raise Diva::InvalidTypeError, "The value is not a `#{name}'."
100
122
  end
101
123
  end
102
- BOOL = AtomicType.new(:bool) do |v|
124
+ BOOL = AtomicType.new(:bool, [TrueClass, FalseClass]) do |v|
103
125
  case v
104
126
  when TrueClass, FalseClass
105
127
  v
@@ -111,7 +133,7 @@ module Diva::Type
111
133
  raise Diva::InvalidTypeError, "The value is not a `#{name}'."
112
134
  end
113
135
  end
114
- STRING = AtomicType.new(:string) do |v|
136
+ STRING = AtomicType.new(:string, String) do |v|
115
137
  case v
116
138
  when Diva::Model, Enumerable
117
139
  raise Diva::InvalidTypeError, "The value is not a `#{name}'."
@@ -124,7 +146,7 @@ module Diva::Type
124
146
  cast(value).iso8601
125
147
  end
126
148
  end
127
- TIME = TimeType.new(:time) do |v|
149
+ TIME = TimeType.new(:time, [Time, String]) do |v|
128
150
  case v
129
151
  when Time
130
152
  v
@@ -136,7 +158,7 @@ module Diva::Type
136
158
  raise Diva::InvalidTypeError, "The value is not a `#{name}'."
137
159
  end
138
160
  end
139
- URI = AtomicType.new(:uri) do |v|
161
+ URI = AtomicType.new(:uri, [Diva::URI, Addressable::URI, ::URI::Generic]) do |v|
140
162
  case v
141
163
  when Diva::URI, Addressable::URI, ::URI::Generic
142
164
  v
@@ -146,6 +168,13 @@ module Diva::Type
146
168
  raise Diva::InvalidTypeError, "The value is not a `#{name}'."
147
169
  end
148
170
  end
171
+ NULL = AtomicType.new(:null, NilClass) do |v|
172
+ if v.nil?
173
+ v
174
+ else
175
+ raise Diva::InvalidTypeError, "The value is not a `#{name}'."
176
+ end
177
+ end
149
178
 
150
179
  class ModelType < MetaType
151
180
  attr_reader :model
@@ -154,6 +183,10 @@ module Diva::Type
154
183
  @model = model
155
184
  end
156
185
 
186
+ def recommendation_point(v)
187
+ v.is_a?(model) && 0
188
+ end
189
+
157
190
  def cast(value)
158
191
  case value
159
192
  when model
@@ -165,9 +198,17 @@ module Diva::Type
165
198
  end
166
199
  end
167
200
 
201
+ def schema
202
+ @schema ||= {type: uri}.freeze
203
+ end
204
+
168
205
  def to_s
169
206
  "#{model} #{name}"
170
207
  end
208
+
209
+ def uri
210
+ model.uri
211
+ end
171
212
  end
172
213
 
173
214
  class ArrayType < MetaType
@@ -177,6 +218,10 @@ module Diva::Type
177
218
  @type = type
178
219
  end
179
220
 
221
+ def recommendation_point(values)
222
+ values.is_a?(Enumerable) && values.all?{|v| @type.recommendation_point(v) } && 0
223
+ end
224
+
180
225
  def cast(value)
181
226
  raise Diva::InvalidTypeError, "The value is not a `#{name}'." unless value.is_a?(Enumerable)
182
227
  value.to_a.map(&@type.method(:cast))
@@ -189,35 +234,55 @@ module Diva::Type
189
234
  def to_s
190
235
  "Array of #{@type.to_s}"
191
236
  end
237
+
238
+ def schema
239
+ @schema ||= { array: @type.schema }.freeze
240
+ end
192
241
  end
193
242
 
194
- class OptionalType < MetaType
195
- def initialize(type)
196
- super("optional_#{type.name}")
197
- @type = type
243
+ class UnionType < MetaType
244
+ def initialize(*types)
245
+ @types = types.flatten.map(&Diva.method(:Type)).freeze
246
+ super("union_#{@types.map(&:name).join('_')}")
247
+ end
248
+
249
+ def recommendation_point(v)
250
+ @types.map{|t| t.recommendation_point(v) }.compact.min
198
251
  end
199
252
 
200
253
  def cast(value)
201
- if value.nil?
202
- value
203
- else
204
- @type.cast(value)
205
- end
254
+ recommended_type_of(value).cast(value)
206
255
  end
207
256
 
208
257
  def dump_for_json(value)
209
- if value.nil?
210
- value
211
- else
212
- @type.dump_for_json(value)
213
- end
258
+ recommended_type_of(value).dump_for_json(value)
214
259
  end
215
260
 
216
261
  def to_s
217
- "#{@type.to_s}|nil"
262
+ @types.map(&:name).join('|').freeze
263
+ end
264
+
265
+ def schema
266
+ @schema ||= { union: @types.map(&:schema) }.freeze
218
267
  end
219
- end
220
268
 
269
+ def recommended_type_of(value)
270
+ @types.map{|t|
271
+ [t, t.recommendation_point(value)]
272
+ }.select{|_,p| p }.sort_by{|_,p| p }.each{|t,_|
273
+ return t
274
+ }
275
+ @types.each do |type|
276
+ begin
277
+ type.cast(value)
278
+ return type
279
+ rescue Diva::InvalidTypeError
280
+ # try next
281
+ end
282
+ end
283
+ raise Diva::InvalidTypeError, "The value is not #{self}"
284
+ end
285
+ end
221
286
  end
222
287
 
223
288
  module Diva
@@ -237,10 +302,16 @@ module Diva
237
302
  Diva::Type::TIME
238
303
  when :uri
239
304
  Diva::Type::URI
305
+ when :null
306
+ Diva::Type::NULL
240
307
  when ->x{x.class == Class && x.ancestors.include?(Diva::Model) }
241
308
  Diva::Type.model_of(type)
242
309
  when Array
243
- Diva::Type.array_of(type.first)
310
+ if type.size >= 2
311
+ Diva::Type.union(*type)
312
+ else
313
+ Diva::Type.array_of(type.first)
314
+ end
244
315
  else
245
316
  fail "Invalid type #{type.inspect} (#{type.class})."
246
317
  end
@@ -32,6 +32,7 @@ require 'addressable/uri'
32
32
 
33
33
  class Diva::URI
34
34
  def initialize(uri)
35
+ @uri = @uri_string = @uri_hash = nil
35
36
  case uri.freeze
36
37
  when URI, Addressable::URI
37
38
  @uri = uri
@@ -96,8 +97,8 @@ class Diva::URI
96
97
  super
97
98
  end
98
99
 
99
- def respond_to?(method)
100
- super or to_uri.respond_to?(method)
100
+ def respond_to_missing?(method, include_private)
101
+ to_uri.respond_to?(method, include_private)
101
102
  end
102
103
 
103
104
  def method_missing(method, *rest, &block)
@@ -1,3 +1,3 @@
1
1
  module Diva
2
- VERSION = "0.3.2"
2
+ VERSION = "1.0.0"
3
3
  end
metadata CHANGED
@@ -1,105 +1,135 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: diva
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Toshiaki Asai
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-04-29 00:00:00.000000000 Z
11
+ date: 2019-06-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 1.16.1
20
+ - - "<"
18
21
  - !ruby/object:Gem::Version
19
- version: '1.12'
22
+ version: '2.1'
20
23
  type: :development
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
- - - "~>"
27
+ - - ">="
25
28
  - !ruby/object:Gem::Version
26
- version: '1.12'
29
+ version: 1.16.1
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '2.1'
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: rake
29
35
  requirement: !ruby/object:Gem::Requirement
30
36
  requirements:
31
- - - "~>"
37
+ - - ">="
32
38
  - !ruby/object:Gem::Version
33
- version: '10.0'
39
+ version: 12.3.2
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '13.0'
34
43
  type: :development
35
44
  prerelease: false
36
45
  version_requirements: !ruby/object:Gem::Requirement
37
46
  requirements:
38
- - - "~>"
47
+ - - ">="
39
48
  - !ruby/object:Gem::Version
40
- version: '10.0'
49
+ version: 12.3.2
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '13.0'
41
53
  - !ruby/object:Gem::Dependency
42
54
  name: minitest
43
55
  requirement: !ruby/object:Gem::Requirement
44
56
  requirements:
45
- - - "~>"
57
+ - - ">="
46
58
  - !ruby/object:Gem::Version
47
- version: '5.0'
59
+ version: 5.11.3
60
+ - - "<"
61
+ - !ruby/object:Gem::Version
62
+ version: '5.12'
48
63
  type: :development
49
64
  prerelease: false
50
65
  version_requirements: !ruby/object:Gem::Requirement
51
66
  requirements:
52
- - - "~>"
67
+ - - ">="
53
68
  - !ruby/object:Gem::Version
54
- version: '5.0'
69
+ version: 5.11.3
70
+ - - "<"
71
+ - !ruby/object:Gem::Version
72
+ version: '5.12'
55
73
  - !ruby/object:Gem::Dependency
56
74
  name: pry
57
75
  requirement: !ruby/object:Gem::Requirement
58
76
  requirements:
59
77
  - - ">="
60
78
  - !ruby/object:Gem::Version
61
- version: '0'
79
+ version: 0.12.2
80
+ - - "<"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.0'
62
83
  type: :development
63
84
  prerelease: false
64
85
  version_requirements: !ruby/object:Gem::Requirement
65
86
  requirements:
66
87
  - - ">="
67
88
  - !ruby/object:Gem::Version
68
- version: '0'
89
+ version: 0.12.2
90
+ - - "<"
91
+ - !ruby/object:Gem::Version
92
+ version: '1.0'
69
93
  - !ruby/object:Gem::Dependency
70
94
  name: simplecov
71
95
  requirement: !ruby/object:Gem::Requirement
72
96
  requirements:
73
97
  - - ">="
74
98
  - !ruby/object:Gem::Version
75
- version: '0'
99
+ version: 0.16.1
100
+ - - "<"
101
+ - !ruby/object:Gem::Version
102
+ version: '1.0'
76
103
  type: :development
77
104
  prerelease: false
78
105
  version_requirements: !ruby/object:Gem::Requirement
79
106
  requirements:
80
107
  - - ">="
81
108
  - !ruby/object:Gem::Version
82
- version: '0'
109
+ version: 0.16.1
110
+ - - "<"
111
+ - !ruby/object:Gem::Version
112
+ version: '1.0'
83
113
  - !ruby/object:Gem::Dependency
84
114
  name: addressable
85
115
  requirement: !ruby/object:Gem::Requirement
86
116
  requirements:
87
117
  - - ">="
88
118
  - !ruby/object:Gem::Version
89
- version: '2.5'
119
+ version: 2.5.2
90
120
  - - "<"
91
121
  - !ruby/object:Gem::Version
92
- version: '2.6'
122
+ version: '2.7'
93
123
  type: :runtime
94
124
  prerelease: false
95
125
  version_requirements: !ruby/object:Gem::Requirement
96
126
  requirements:
97
127
  - - ">="
98
128
  - !ruby/object:Gem::Version
99
- version: '2.5'
129
+ version: 2.5.2
100
130
  - - "<"
101
131
  - !ruby/object:Gem::Version
102
- version: '2.6'
132
+ version: '2.7'
103
133
  description:
104
134
  email:
105
135
  - toshi.alternative@gmail.com
@@ -117,7 +147,6 @@ files:
117
147
  - bin/setup
118
148
  - diva.gemspec
119
149
  - lib/diva.rb
120
- - lib/diva/combinator.rb
121
150
  - lib/diva/datasource.rb
122
151
  - lib/diva/error.rb
123
152
  - lib/diva/field.rb
@@ -147,8 +176,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
147
176
  - !ruby/object:Gem::Version
148
177
  version: '0'
149
178
  requirements: []
150
- rubyforge_project:
151
- rubygems_version: 2.7.6
179
+ rubygems_version: 3.0.3
152
180
  signing_key:
153
181
  specification_version: 4
154
182
  summary: Implementation of expression for handling things.
@@ -1,106 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- module Diva::Combinable
4
- class Combinator
5
- def initialize(a, b)
6
- @a, @b = a, b
7
- end
8
-
9
- # コンストラクタに渡された二つの値が _behavior_ をサポートしていれば真を返す
10
- # ==== Args
11
- # [behavior] 想定する振る舞い(Symbol)
12
- # ==== Return
13
- # true or false
14
- def =~(behavior)
15
- fail 'Not implement'
16
- end
17
-
18
- def ===(behavior)
19
- self =~ behavior
20
- end
21
-
22
- # このCombinatorが持っている値のすべての組み合わせのうち、適切に _behavior_
23
- # をサポートしている組み合わせについて繰り返すEnumeratorを返す
24
- # ==== Args
25
- # [behavior] 想定する振る舞い(Symbol)
26
- # ==== Return
27
- # [レシーバ, 引数] のペアを列挙するEnumerator
28
- def enum(behavior)
29
- Enumerator.new do |yielder|
30
- yielder << [@a, @b] if a_b(behavior)
31
- yielder << [@b, @a] if b_a(behavior)
32
- end
33
- end
34
-
35
- def method_missing(behavior, *rest)
36
- if rest.empty?
37
- return self =~ behavior
38
- end
39
- super
40
- end
41
-
42
- private
43
-
44
- def a_b(behavior)
45
- @a.respond_to?(behavior) && @a.__send__(behavior, @b)
46
- end
47
-
48
- def b_a(behavior)
49
- @b.respond_to?(behavior) && @b.__send__(behavior, @a)
50
- end
51
- end
52
-
53
- class PluralCombinator < Combinator
54
- def enum(behavior)
55
- Enumerator.new do |yielder|
56
- @b.each do |b|
57
- (b | @a).enum(behavior).each(&yielder.method(:<<))
58
- end
59
- end
60
- end
61
- end
62
-
63
- class SingleCombinator < Combinator
64
- def =~(behavior)
65
- a_b(behavior) || b_a(behavior)
66
- end
67
- end
68
-
69
- class AnyCombinator < PluralCombinator
70
- def =~(behavior)
71
- @b.any?{|b| b | @a =~ behavior }
72
- end
73
- end
74
-
75
- class AllCombinator < PluralCombinator
76
- def =~(behavior)
77
- @b.all?{|b| b | @a =~ behavior }
78
- end
79
- end
80
-
81
- # _other_ との Diva::Conbinable::Combinator を生成する
82
- # ==== Args
83
- # [other] Diva::Modelか、Diva::Modelを列挙するEnumerable
84
- # ==== Return
85
- # Diva::Conbinable::Combinator
86
- def |(other)
87
- if other.is_a? Enumerable
88
- AnyCombinator.new(self, other)
89
- else
90
- SingleCombinator.new(self, other)
91
- end
92
- end
93
-
94
- # _other_ との Diva::Conbinable::Combinator を生成する
95
- # ==== Args
96
- # [other] Diva::Modelか、Diva::Modelを列挙するEnumerable
97
- # ==== Return
98
- # Diva::Conbinable::Combinator
99
- def &(other)
100
- if other.is_a? Enumerable
101
- AllCombinator.new(self, other)
102
- else
103
- SingleCombinator.new(self, other)
104
- end
105
- end
106
- end