sumaki 0.2.0 → 0.4.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/.rubocop.yml +2 -2
- data/Gemfile.lock +14 -12
- data/README.md +69 -6
- data/lib/sumaki/adapter/hash.rb +16 -0
- data/lib/sumaki/model/associations/association.rb +53 -0
- data/lib/sumaki/model/associations/collection.rb +53 -0
- data/lib/sumaki/model/associations/reflection.rb +64 -0
- data/lib/sumaki/model/associations.rb +159 -0
- data/lib/sumaki/model/enum.rb +11 -6
- data/lib/sumaki/model/fields/reflection.rb +24 -0
- data/lib/sumaki/model/fields/type/boolean.rb +31 -0
- data/lib/sumaki/model/fields/type/date.rb +35 -0
- data/lib/sumaki/model/fields/type/date_time.rb +35 -0
- data/lib/sumaki/model/fields/type/float.rb +23 -0
- data/lib/sumaki/model/fields/type/integer.rb +23 -0
- data/lib/sumaki/model/fields/type/string.rb +23 -0
- data/lib/sumaki/model/fields/type/value.rb +32 -0
- data/lib/sumaki/model/fields/type.rb +50 -0
- data/lib/sumaki/model/fields.rb +137 -0
- data/lib/sumaki/model.rb +70 -4
- data/lib/sumaki/version.rb +1 -1
- metadata +16 -4
- data/lib/sumaki/model/association.rb +0 -116
- data/lib/sumaki/model/attribute.rb +0 -43
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'value'
|
4
|
+
require 'date'
|
5
|
+
|
6
|
+
module Sumaki
|
7
|
+
module Model
|
8
|
+
module Fields
|
9
|
+
module Type
|
10
|
+
class DateError < Error; end
|
11
|
+
|
12
|
+
class Date < Value # :nodoc:
|
13
|
+
def self.serialize(value)
|
14
|
+
value.nil? ? nil : cast(value)
|
15
|
+
rescue ::Date::Error
|
16
|
+
raise DateError
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.deserialize(value)
|
20
|
+
value.nil? ? nil : cast(value)
|
21
|
+
rescue ::Date::Error
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.cast(value)
|
26
|
+
return value.to_date if value.respond_to?(:to_date)
|
27
|
+
|
28
|
+
::Date.parse(value.to_s)
|
29
|
+
end
|
30
|
+
private_class_method :cast
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'value'
|
4
|
+
require 'date'
|
5
|
+
|
6
|
+
module Sumaki
|
7
|
+
module Model
|
8
|
+
module Fields
|
9
|
+
module Type
|
10
|
+
class DateError < Error; end
|
11
|
+
|
12
|
+
class DateTime < Value # :nodoc:
|
13
|
+
def self.serialize(value)
|
14
|
+
value.nil? ? nil : cast(value)
|
15
|
+
rescue ::Date::Error
|
16
|
+
raise DateError
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.deserialize(value)
|
20
|
+
value.nil? ? nil : cast(value)
|
21
|
+
rescue ::Date::Error
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.cast(value)
|
26
|
+
return value.to_datetime if value.respond_to?(:to_datetime)
|
27
|
+
|
28
|
+
::DateTime.parse(value.to_s)
|
29
|
+
end
|
30
|
+
private_class_method :cast
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'value'
|
4
|
+
|
5
|
+
module Sumaki
|
6
|
+
module Model
|
7
|
+
module Fields
|
8
|
+
module Type
|
9
|
+
class Float < Value # :nodoc:
|
10
|
+
def self.serialize(value)
|
11
|
+
try_casting do
|
12
|
+
value.nil? ? nil : Float(value)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.deserialize(value)
|
17
|
+
value.nil? ? nil : Float(value, exception: false)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'value'
|
4
|
+
|
5
|
+
module Sumaki
|
6
|
+
module Model
|
7
|
+
module Fields
|
8
|
+
module Type
|
9
|
+
class Integer < Value # :nodoc:
|
10
|
+
def self.serialize(value)
|
11
|
+
try_casting do
|
12
|
+
value.nil? ? nil : Integer(value)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.deserialize(value)
|
17
|
+
value.nil? ? nil : Integer(value, exception: false)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'value'
|
4
|
+
|
5
|
+
module Sumaki
|
6
|
+
module Model
|
7
|
+
module Fields
|
8
|
+
module Type
|
9
|
+
class String < Value # :nodoc:
|
10
|
+
def self.serialize(value)
|
11
|
+
try_casting do
|
12
|
+
value.nil? ? nil : String(value)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.deserialize(value)
|
17
|
+
value.nil? ? nil : String(value)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sumaki
|
4
|
+
module Model
|
5
|
+
module Fields
|
6
|
+
module Type
|
7
|
+
class Error < StandardError; end
|
8
|
+
class ArgumentError < Error; end
|
9
|
+
class TypeError < Error; end
|
10
|
+
|
11
|
+
class Value # :nodoc:
|
12
|
+
def self.serialize(value)
|
13
|
+
value
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.deserialize(value)
|
17
|
+
value
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.try_casting
|
21
|
+
yield
|
22
|
+
rescue ::ArgumentError
|
23
|
+
raise Type::ArgumentError
|
24
|
+
rescue ::TypeError
|
25
|
+
raise Type::TypeError
|
26
|
+
end
|
27
|
+
private_class_method :try_casting
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'type/value'
|
4
|
+
require_relative 'type/integer'
|
5
|
+
require_relative 'type/float'
|
6
|
+
require_relative 'type/string'
|
7
|
+
require_relative 'type/boolean'
|
8
|
+
require_relative 'type/date'
|
9
|
+
require_relative 'type/date_time'
|
10
|
+
|
11
|
+
module Sumaki
|
12
|
+
module Model
|
13
|
+
module Fields
|
14
|
+
module Type # :nodoc:
|
15
|
+
class Types # :nodoc:
|
16
|
+
def initialize
|
17
|
+
@types = {}
|
18
|
+
end
|
19
|
+
|
20
|
+
def register(name, type_class)
|
21
|
+
@types[name] = type_class
|
22
|
+
end
|
23
|
+
|
24
|
+
def lookup(type_name)
|
25
|
+
@types.fetch(type_name)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
@types = Types.new
|
30
|
+
|
31
|
+
def register(...)
|
32
|
+
@types.register(...)
|
33
|
+
end
|
34
|
+
|
35
|
+
def lookup(...)
|
36
|
+
@types.lookup(...)
|
37
|
+
end
|
38
|
+
|
39
|
+
module_function :register, :lookup
|
40
|
+
|
41
|
+
register(:int, Integer)
|
42
|
+
register(:float, Float)
|
43
|
+
register(:string, String)
|
44
|
+
register(:bool, Boolean)
|
45
|
+
register(:date, Date)
|
46
|
+
register(:datetime, DateTime)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'fields/reflection'
|
4
|
+
|
5
|
+
module Sumaki
|
6
|
+
module Model
|
7
|
+
# = Sumaki::Model::Fields
|
8
|
+
module Fields
|
9
|
+
def self.included(base)
|
10
|
+
base.extend ClassMethods
|
11
|
+
base.include InstanceMethods
|
12
|
+
end
|
13
|
+
|
14
|
+
class FieldAccessor # :nodoc:
|
15
|
+
def initialize(model)
|
16
|
+
@model = model
|
17
|
+
end
|
18
|
+
|
19
|
+
def get(field_name)
|
20
|
+
reflection = @model.class.field_reflections[field_name]
|
21
|
+
|
22
|
+
value = @model.get(reflection.name)
|
23
|
+
reflection.type_class.deserialize(value)
|
24
|
+
end
|
25
|
+
|
26
|
+
def set(field_name, value)
|
27
|
+
reflection = @model.class.field_reflections[field_name]
|
28
|
+
|
29
|
+
serialized = reflection.type_class.serialize(value)
|
30
|
+
@model.set(reflection.name, serialized)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module AccessorAdder # :nodoc:
|
35
|
+
def add(model_class, methods_module, reflection)
|
36
|
+
add_getter(methods_module, reflection.name)
|
37
|
+
add_setter(methods_module, reflection.name)
|
38
|
+
|
39
|
+
model_class.field_reflections[reflection.name] = reflection
|
40
|
+
end
|
41
|
+
|
42
|
+
def add_getter(methods_module, field_name)
|
43
|
+
methods_module.module_eval <<~RUBY, __FILE__, __LINE__ + 1
|
44
|
+
def #{field_name} # def title
|
45
|
+
field_accessor.get(:'#{field_name}') # field_accessor.get(:'title')
|
46
|
+
end # end
|
47
|
+
RUBY
|
48
|
+
end
|
49
|
+
|
50
|
+
def add_setter(methods_module, field_name)
|
51
|
+
methods_module.module_eval <<~RUBY, __FILE__, __LINE__ + 1
|
52
|
+
def #{field_name}=(value) # def title=(value)
|
53
|
+
field_accessor.set(:'#{field_name}', value) # field_accessor.set(:'title', value)
|
54
|
+
end # end
|
55
|
+
RUBY
|
56
|
+
end
|
57
|
+
module_function :add, :add_getter, :add_setter
|
58
|
+
end
|
59
|
+
|
60
|
+
module ClassMethods # :nodoc:
|
61
|
+
# Access to the field.
|
62
|
+
#
|
63
|
+
# class Anime
|
64
|
+
# include Sumaki::Model
|
65
|
+
# field :title
|
66
|
+
# field :url
|
67
|
+
# end
|
68
|
+
#
|
69
|
+
# anime = Anime.new({ title: 'The Vampire Dies in No Time', url: 'https://sugushinu-anime.jp/' })
|
70
|
+
# anime.title #=> 'The Vampire Dies in No Time'
|
71
|
+
# anime.url #=> 'https://sugushinu-anime.jp/'
|
72
|
+
#
|
73
|
+
# The Field value cam be set.
|
74
|
+
#
|
75
|
+
# anime = Anime.new({})
|
76
|
+
# anime.title = 'The Vampire Dies in No Time'
|
77
|
+
# anime.title #=> 'The Vampire Dies in No Time'
|
78
|
+
#
|
79
|
+
# == Type casting
|
80
|
+
#
|
81
|
+
# When a type is specified, it will be typecast.
|
82
|
+
#
|
83
|
+
# class Character
|
84
|
+
# include Sumaki::Model
|
85
|
+
#
|
86
|
+
# field :age, :int
|
87
|
+
# end
|
88
|
+
#
|
89
|
+
# character = Character.new({ age: '208' })
|
90
|
+
# character.age #=> 208
|
91
|
+
#
|
92
|
+
# Types are:
|
93
|
+
#
|
94
|
+
# * <tt>:int</tt>
|
95
|
+
# * <tt>:float</tt>
|
96
|
+
# * <tt>:string</tt>
|
97
|
+
# * <tt>:bool</tt>
|
98
|
+
# * <tt>:date</tt>
|
99
|
+
# * <tt>:datetime</tt>
|
100
|
+
def field(name, type = nil)
|
101
|
+
reflection = Reflection.new(name, type)
|
102
|
+
AccessorAdder.add(self, attribute_methods_module, reflection)
|
103
|
+
end
|
104
|
+
|
105
|
+
def field_names
|
106
|
+
field_reflections.keys
|
107
|
+
end
|
108
|
+
|
109
|
+
def field_reflections
|
110
|
+
@field_reflections ||= {}
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
def attribute_methods_module
|
116
|
+
@attribute_methods_module ||= begin
|
117
|
+
mod = Module.new
|
118
|
+
include mod
|
119
|
+
mod
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
module InstanceMethods # :nodoc:
|
125
|
+
def fields
|
126
|
+
self.class.field_names.map.with_object({}) { |e, r| r[e] = public_send(e) }
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
def field_accessor
|
132
|
+
@field_accessor ||= FieldAccessor.new(self)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
data/lib/sumaki/model.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'model/
|
4
|
-
require_relative 'model/
|
3
|
+
require_relative 'model/fields'
|
4
|
+
require_relative 'model/associations'
|
5
5
|
require_relative 'model/enum'
|
6
6
|
|
7
7
|
module Sumaki
|
@@ -163,8 +163,8 @@ module Sumaki
|
|
163
163
|
base.extend ClassMethods
|
164
164
|
base.include InstanceMethods
|
165
165
|
|
166
|
-
base.include
|
167
|
-
base.include
|
166
|
+
base.include Fields
|
167
|
+
base.include Associations
|
168
168
|
base.include Enum
|
169
169
|
end
|
170
170
|
|
@@ -177,6 +177,33 @@ module Sumaki
|
|
177
177
|
end
|
178
178
|
end
|
179
179
|
|
180
|
+
class ObjectAccessor # :nodoc:
|
181
|
+
def initialize(object, adapter)
|
182
|
+
@object = object
|
183
|
+
@adapter = adapter
|
184
|
+
end
|
185
|
+
|
186
|
+
def get(name)
|
187
|
+
@adapter.get(@object, name)
|
188
|
+
end
|
189
|
+
|
190
|
+
def set(name, value)
|
191
|
+
@adapter.set(@object, name, value)
|
192
|
+
end
|
193
|
+
|
194
|
+
def build_singular(name)
|
195
|
+
@adapter.build_singular(@object, name)
|
196
|
+
end
|
197
|
+
|
198
|
+
def build_repeated_element(name)
|
199
|
+
@adapter.build_repeated_element(@object, name)
|
200
|
+
end
|
201
|
+
|
202
|
+
def apply_repeated(name, models)
|
203
|
+
@adapter.apply_repeated(@object, name, models.map(&:object))
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
180
207
|
module InstanceMethods # :nodoc:
|
181
208
|
attr_reader :object, :parent
|
182
209
|
|
@@ -184,6 +211,45 @@ module Sumaki
|
|
184
211
|
@object = object
|
185
212
|
@parent = parent
|
186
213
|
end
|
214
|
+
|
215
|
+
def object_accessor
|
216
|
+
@object_accessor ||= ObjectAccessor.new(object, self.class.adapter)
|
217
|
+
end
|
218
|
+
|
219
|
+
def get(name)
|
220
|
+
object_accessor.get(name)
|
221
|
+
end
|
222
|
+
|
223
|
+
def set(name, value)
|
224
|
+
object_accessor.set(name, value)
|
225
|
+
end
|
226
|
+
|
227
|
+
def assign(attrs)
|
228
|
+
attrs.each do |attr, value|
|
229
|
+
public_send(:"#{attr}=", value)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
def inspect
|
234
|
+
inspection = fields
|
235
|
+
.map { |name, value| "#{name}: #{value.inspect}" }
|
236
|
+
.join(', ')
|
237
|
+
"#<#{self.class.name} #{inspection}>"
|
238
|
+
end
|
239
|
+
|
240
|
+
def pretty_print(pp) # rubocop:disable Metrics/MethodLength
|
241
|
+
pp.object_address_group(self) do
|
242
|
+
pp.seplist(fields, -> { pp.text ',' }) do |field, value|
|
243
|
+
pp.breakable
|
244
|
+
pp.group(1) do
|
245
|
+
pp.text field.to_s
|
246
|
+
pp.text ':'
|
247
|
+
pp.breakable
|
248
|
+
pp.pp value
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
187
253
|
end
|
188
254
|
end
|
189
255
|
end
|
data/lib/sumaki/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sumaki
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Loose Coupling
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-05-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minenum
|
@@ -48,9 +48,21 @@ files:
|
|
48
48
|
- lib/sumaki/adapter/hash.rb
|
49
49
|
- lib/sumaki/config.rb
|
50
50
|
- lib/sumaki/model.rb
|
51
|
-
- lib/sumaki/model/
|
52
|
-
- lib/sumaki/model/
|
51
|
+
- lib/sumaki/model/associations.rb
|
52
|
+
- lib/sumaki/model/associations/association.rb
|
53
|
+
- lib/sumaki/model/associations/collection.rb
|
54
|
+
- lib/sumaki/model/associations/reflection.rb
|
53
55
|
- lib/sumaki/model/enum.rb
|
56
|
+
- lib/sumaki/model/fields.rb
|
57
|
+
- lib/sumaki/model/fields/reflection.rb
|
58
|
+
- lib/sumaki/model/fields/type.rb
|
59
|
+
- lib/sumaki/model/fields/type/boolean.rb
|
60
|
+
- lib/sumaki/model/fields/type/date.rb
|
61
|
+
- lib/sumaki/model/fields/type/date_time.rb
|
62
|
+
- lib/sumaki/model/fields/type/float.rb
|
63
|
+
- lib/sumaki/model/fields/type/integer.rb
|
64
|
+
- lib/sumaki/model/fields/type/string.rb
|
65
|
+
- lib/sumaki/model/fields/type/value.rb
|
54
66
|
- lib/sumaki/version.rb
|
55
67
|
- sig/sumaki.rbs
|
56
68
|
homepage: https://github.com/nowlinuxing/sumaki/
|
@@ -1,116 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Sumaki
|
4
|
-
module Model
|
5
|
-
# = Sumaki::Model::Association
|
6
|
-
module Association
|
7
|
-
def self.included(base)
|
8
|
-
base.extend ClassMethods
|
9
|
-
base.include InstanceMethods
|
10
|
-
|
11
|
-
base.instance_variable_set(:@classes, {})
|
12
|
-
end
|
13
|
-
|
14
|
-
module ClassMethods # :nodoc:
|
15
|
-
# Access to the sub object.
|
16
|
-
#
|
17
|
-
# class Book
|
18
|
-
# include Sumaki::Model
|
19
|
-
# singular :company
|
20
|
-
#
|
21
|
-
# class Company
|
22
|
-
# include Sumaki::Model
|
23
|
-
# end
|
24
|
-
# end
|
25
|
-
#
|
26
|
-
# data = {
|
27
|
-
# title: 'The Ronaldo Chronicles',
|
28
|
-
# company: {
|
29
|
-
# name: 'Autumn Books',
|
30
|
-
# }
|
31
|
-
# }
|
32
|
-
# book = Book.new(data)
|
33
|
-
# book.company.class #=> Book::Company
|
34
|
-
#
|
35
|
-
# == Options
|
36
|
-
#
|
37
|
-
# [:class_name]
|
38
|
-
# Specify the name of the class to wrap. Use this if the name of the class
|
39
|
-
# to wrap is not inferred from the nested field names.
|
40
|
-
def singular(name, class_name: nil)
|
41
|
-
association_methods_module.define_method(name) do
|
42
|
-
klass = self.class.class_for(name, class_name)
|
43
|
-
klass.new(get(name), parent: self)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
# Access to the repeated sub objects
|
48
|
-
#
|
49
|
-
# class Company
|
50
|
-
# include Sumaki::Model
|
51
|
-
# repeated :member
|
52
|
-
#
|
53
|
-
# class Member
|
54
|
-
# include Sumaki::Model
|
55
|
-
# end
|
56
|
-
# end
|
57
|
-
#
|
58
|
-
# data = {
|
59
|
-
# name: 'The Ronaldo Vampire Hunter Agency',
|
60
|
-
# member: [
|
61
|
-
# { name: 'Ronaldo' },
|
62
|
-
# { name: 'Draluc' },
|
63
|
-
# { name: 'John' }
|
64
|
-
# ]
|
65
|
-
# }
|
66
|
-
# company = Company.new(data)
|
67
|
-
# company.member[2].class #=> Company::Member
|
68
|
-
#
|
69
|
-
# == Options
|
70
|
-
#
|
71
|
-
# [:class_name]
|
72
|
-
# Specify the name of the class to wrap. Use this if the name of the class
|
73
|
-
# to wrap is not inferred from the nested field names.
|
74
|
-
def repeated(name, class_name: nil)
|
75
|
-
association_methods_module.define_method(name) do
|
76
|
-
klass = self.class.class_for(name, class_name)
|
77
|
-
get(name).map { |object| klass.new(object, parent: self) }
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def class_for(name, class_name = nil)
|
82
|
-
return @classes[name] if @classes.key?(name)
|
83
|
-
|
84
|
-
basename = class_name || classify(name.to_s)
|
85
|
-
klass = if const_defined?(basename)
|
86
|
-
const_get(basename)
|
87
|
-
else
|
88
|
-
const_set(basename, Class.new { include Model })
|
89
|
-
end
|
90
|
-
klass.parent ||= self
|
91
|
-
@classes[name] = klass
|
92
|
-
end
|
93
|
-
|
94
|
-
private
|
95
|
-
|
96
|
-
def association_methods_module
|
97
|
-
@association_methods_module ||= begin
|
98
|
-
mod = Module.new
|
99
|
-
include mod
|
100
|
-
mod
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
def classify(key)
|
105
|
-
key.gsub(/([a-z\d]+)_?/) { |_| Regexp.last_match(1).capitalize }
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
module InstanceMethods # :nodoc:
|
110
|
-
def get(name)
|
111
|
-
self.class.adapter.get(object, name)
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
@@ -1,43 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Sumaki
|
4
|
-
module Model
|
5
|
-
# = Sumaki::Model::Attribute
|
6
|
-
module Attribute
|
7
|
-
def self.included(base)
|
8
|
-
base.extend ClassMethods
|
9
|
-
end
|
10
|
-
|
11
|
-
module ClassMethods # :nodoc:
|
12
|
-
# Access to the field.
|
13
|
-
#
|
14
|
-
# class Anime
|
15
|
-
# include Sumaki::Model
|
16
|
-
# field :title
|
17
|
-
# field :url
|
18
|
-
# end
|
19
|
-
#
|
20
|
-
# anime = Anime.new({ title: 'The Vampire Dies in No Time', url: 'https://sugushinu-anime.jp/' })
|
21
|
-
# anime.title #=> 'The Vampire Dies in No Time'
|
22
|
-
# anime.url #=> 'https://sugushinu-anime.jp/'
|
23
|
-
def field(name)
|
24
|
-
attribute_methods_module.module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
25
|
-
def #{name} # def title
|
26
|
-
get(:'#{name}') # get(:'title')
|
27
|
-
end # end
|
28
|
-
RUBY
|
29
|
-
end
|
30
|
-
|
31
|
-
private
|
32
|
-
|
33
|
-
def attribute_methods_module
|
34
|
-
@attribute_methods_module ||= begin
|
35
|
-
mod = Module.new
|
36
|
-
include mod
|
37
|
-
mod
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|