hanami-model 0.0.0 → 0.6.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/CHANGELOG.md +145 -0
- data/EXAMPLE.md +212 -0
- data/LICENSE.md +22 -0
- data/README.md +600 -7
- data/hanami-model.gemspec +17 -12
- data/lib/hanami-model.rb +1 -0
- data/lib/hanami/entity.rb +298 -0
- data/lib/hanami/entity/dirty_tracking.rb +74 -0
- data/lib/hanami/model.rb +204 -2
- data/lib/hanami/model/adapters/abstract.rb +281 -0
- data/lib/hanami/model/adapters/file_system_adapter.rb +288 -0
- data/lib/hanami/model/adapters/implementation.rb +111 -0
- data/lib/hanami/model/adapters/memory/collection.rb +132 -0
- data/lib/hanami/model/adapters/memory/command.rb +113 -0
- data/lib/hanami/model/adapters/memory/query.rb +653 -0
- data/lib/hanami/model/adapters/memory_adapter.rb +179 -0
- data/lib/hanami/model/adapters/null_adapter.rb +24 -0
- data/lib/hanami/model/adapters/sql/collection.rb +287 -0
- data/lib/hanami/model/adapters/sql/command.rb +73 -0
- data/lib/hanami/model/adapters/sql/console.rb +33 -0
- data/lib/hanami/model/adapters/sql/consoles/mysql.rb +49 -0
- data/lib/hanami/model/adapters/sql/consoles/postgresql.rb +48 -0
- data/lib/hanami/model/adapters/sql/consoles/sqlite.rb +26 -0
- data/lib/hanami/model/adapters/sql/query.rb +788 -0
- data/lib/hanami/model/adapters/sql_adapter.rb +296 -0
- data/lib/hanami/model/coercer.rb +74 -0
- data/lib/hanami/model/config/adapter.rb +116 -0
- data/lib/hanami/model/config/mapper.rb +45 -0
- data/lib/hanami/model/configuration.rb +275 -0
- data/lib/hanami/model/error.rb +7 -0
- data/lib/hanami/model/mapper.rb +124 -0
- data/lib/hanami/model/mapping.rb +48 -0
- data/lib/hanami/model/mapping/attribute.rb +85 -0
- data/lib/hanami/model/mapping/coercers.rb +314 -0
- data/lib/hanami/model/mapping/collection.rb +490 -0
- data/lib/hanami/model/mapping/collection_coercer.rb +79 -0
- data/lib/hanami/model/migrator.rb +324 -0
- data/lib/hanami/model/migrator/adapter.rb +170 -0
- data/lib/hanami/model/migrator/connection.rb +133 -0
- data/lib/hanami/model/migrator/mysql_adapter.rb +72 -0
- data/lib/hanami/model/migrator/postgres_adapter.rb +119 -0
- data/lib/hanami/model/migrator/sqlite_adapter.rb +110 -0
- data/lib/hanami/model/version.rb +4 -1
- data/lib/hanami/repository.rb +872 -0
- metadata +100 -16
- data/.gitignore +0 -9
- data/Gemfile +0 -4
- data/Rakefile +0 -2
- data/bin/console +0 -14
- data/bin/setup +0 -8
data/hanami-model.gemspec
CHANGED
@@ -4,20 +4,25 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
require 'hanami/model/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
7
|
+
spec.name = 'hanami-model'
|
8
8
|
spec.version = Hanami::Model::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
9
|
+
spec.authors = ['Luca Guidi', 'Trung Lê', 'Alfonso Uceda']
|
10
|
+
spec.email = ['me@lucaguidi.com', 'trung.le@ruby-journal.com', 'uceda73@gmail.com']
|
11
|
+
spec.summary = %q{A persistence layer for Hanami}
|
12
|
+
spec.description = %q{A persistence framework with entities, repositories, data mapper and query objects}
|
13
|
+
spec.homepage = 'http://hanamirb.org'
|
14
|
+
spec.license = 'MIT'
|
11
15
|
|
12
|
-
spec.
|
13
|
-
spec.
|
14
|
-
spec.
|
16
|
+
spec.files = `git ls-files -z -- lib/* CHANGELOG.md EXAMPLE.md LICENSE.md README.md hanami-model.gemspec`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
spec.required_ruby_version = '>= 2.0.0'
|
15
21
|
|
16
|
-
spec.
|
17
|
-
spec.
|
18
|
-
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
|
-
spec.require_paths = ["lib"]
|
22
|
+
spec.add_runtime_dependency 'hanami-utils', '~> 0.7'
|
23
|
+
spec.add_runtime_dependency 'sequel', '~> 4.9'
|
20
24
|
|
21
|
-
spec.add_development_dependency
|
22
|
-
spec.add_development_dependency
|
25
|
+
spec.add_development_dependency 'bundler', '~> 1.6'
|
26
|
+
spec.add_development_dependency 'minitest', '~> 5'
|
27
|
+
spec.add_development_dependency 'rake', '~> 10'
|
23
28
|
end
|
data/lib/hanami-model.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'hanami/model'
|
@@ -0,0 +1,298 @@
|
|
1
|
+
require 'hanami/utils/kernel'
|
2
|
+
require 'hanami/utils/attributes'
|
3
|
+
|
4
|
+
module Hanami
|
5
|
+
# An object that is defined by its identity.
|
6
|
+
# See "Domain Driven Design" by Eric Evans.
|
7
|
+
#
|
8
|
+
# An entity is the core of an application, where the part of the domain
|
9
|
+
# logic is implemented. It's a small, cohesive object that expresses coherent
|
10
|
+
# and meaningful behaviors.
|
11
|
+
#
|
12
|
+
# It deals with one and only one responsibility that is pertinent to the
|
13
|
+
# domain of the application, without caring about details such as persistence
|
14
|
+
# or validations.
|
15
|
+
#
|
16
|
+
# This simplicity of design allows developers to focus on behaviors, or
|
17
|
+
# message passing if you will, which is the quintessence of Object Oriented
|
18
|
+
# Programming.
|
19
|
+
#
|
20
|
+
# @example With Hanami::Entity
|
21
|
+
# require 'hanami/model'
|
22
|
+
#
|
23
|
+
# class Person
|
24
|
+
# include Hanami::Entity
|
25
|
+
# attributes :name, :age
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# When a class includes `Hanami::Entity` it receives the following interface:
|
29
|
+
#
|
30
|
+
# * #id
|
31
|
+
# * #id=
|
32
|
+
# * #initialize(attributes = {})
|
33
|
+
#
|
34
|
+
# `Hanami::Entity` also provides the `.attributes=` for defining attribute accessors for the given names.
|
35
|
+
#
|
36
|
+
# If we expand the code above in **pure Ruby**, it would be:
|
37
|
+
#
|
38
|
+
# @example Pure Ruby
|
39
|
+
# class Person
|
40
|
+
# attr_accessor :id, :name, :age
|
41
|
+
#
|
42
|
+
# def initialize(attributes = {})
|
43
|
+
# @id, @name, @age = attributes.values_at(:id, :name, :age)
|
44
|
+
# end
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# **Hanami::Model** ships `Hanami::Entity` for developers's convenience.
|
48
|
+
#
|
49
|
+
# **Hanami::Model** depends on a narrow and well-defined interface for an
|
50
|
+
# Entity - `#id`, `#id=`, `#initialize(attributes={})`.If your object
|
51
|
+
# implements that interface then that object can be used as an Entity in the
|
52
|
+
# **Hanami::Model** framework.
|
53
|
+
#
|
54
|
+
# However, we suggest to implement this interface by including
|
55
|
+
# `Hanami::Entity`, in case that future versions of the framework will expand
|
56
|
+
# it.
|
57
|
+
#
|
58
|
+
# See Dependency Inversion Principle for more on interfaces.
|
59
|
+
#
|
60
|
+
# @since 0.1.0
|
61
|
+
#
|
62
|
+
# @see Hanami::Repository
|
63
|
+
module Entity
|
64
|
+
# Inject the public API into the hosting class.
|
65
|
+
#
|
66
|
+
# @since 0.1.0
|
67
|
+
#
|
68
|
+
# @example With Object
|
69
|
+
# require 'hanami/model'
|
70
|
+
#
|
71
|
+
# class User
|
72
|
+
# include Hanami::Entity
|
73
|
+
# end
|
74
|
+
#
|
75
|
+
# @example With Struct
|
76
|
+
# require 'hanami/model'
|
77
|
+
#
|
78
|
+
# User = Struct.new(:id, :name) do
|
79
|
+
# include Hanami::Entity
|
80
|
+
# end
|
81
|
+
def self.included(base)
|
82
|
+
base.class_eval do
|
83
|
+
extend ClassMethods
|
84
|
+
attributes :id
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
module ClassMethods
|
89
|
+
# (Re)defines getters, setters and initialization for the given attributes.
|
90
|
+
#
|
91
|
+
# These attributes can match the database columns, but this isn't a
|
92
|
+
# requirement. The mapper used by the relative repository will translate
|
93
|
+
# these names automatically.
|
94
|
+
#
|
95
|
+
# An entity can work with attributes not configured in the mapper, but
|
96
|
+
# of course they will be ignored when the entity will be persisted.
|
97
|
+
#
|
98
|
+
# Please notice that the required `id` attribute is automatically defined
|
99
|
+
# and can be omitted in the arguments.
|
100
|
+
#
|
101
|
+
# @param attrs [Array<Symbol>] a set of arbitrary attribute names
|
102
|
+
#
|
103
|
+
# @since 0.2.0
|
104
|
+
#
|
105
|
+
# @see Hanami::Repository
|
106
|
+
# @see Hanami::Model::Mapper
|
107
|
+
#
|
108
|
+
# @example
|
109
|
+
# require 'hanami/model'
|
110
|
+
#
|
111
|
+
# class User
|
112
|
+
# include Hanami::Entity
|
113
|
+
# attributes :name, :age
|
114
|
+
# end
|
115
|
+
# User.attributes => #<Set: {:id, :name, :age}>
|
116
|
+
#
|
117
|
+
# @example Given params is array of attributes
|
118
|
+
# require 'hanami/model'
|
119
|
+
#
|
120
|
+
# class User
|
121
|
+
# include Hanami::Entity
|
122
|
+
# attributes [:name, :age]
|
123
|
+
# end
|
124
|
+
# User.attributes => #<Set: {:id, :name, :age}>
|
125
|
+
#
|
126
|
+
# @example Extend entity
|
127
|
+
# require 'hanami/model'
|
128
|
+
#
|
129
|
+
# class User
|
130
|
+
# include Hanami::Entity
|
131
|
+
# attributes :name
|
132
|
+
# end
|
133
|
+
#
|
134
|
+
# class DeletedUser < User
|
135
|
+
# include Hanami::Entity
|
136
|
+
# attributes :deleted_at
|
137
|
+
# end
|
138
|
+
#
|
139
|
+
# User.attributes => #<Set: {:id, :name}>
|
140
|
+
# DeletedUser.attributes => #<Set: {:id, :name, :deleted_at}>
|
141
|
+
#
|
142
|
+
def attributes(*attrs)
|
143
|
+
return @attributes ||= Set.new unless attrs.any?
|
144
|
+
|
145
|
+
Hanami::Utils::Kernel.Array(attrs).each do |attr|
|
146
|
+
if allowed_attribute_name?(attr)
|
147
|
+
define_attr_accessor(attr)
|
148
|
+
self.attributes << attr
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# Define setter/getter methods for attributes.
|
154
|
+
#
|
155
|
+
# @param attr [Symbol] an attribute name
|
156
|
+
#
|
157
|
+
# @since 0.3.1
|
158
|
+
# @api private
|
159
|
+
def define_attr_accessor(attr)
|
160
|
+
attr_accessor(attr)
|
161
|
+
end
|
162
|
+
|
163
|
+
# Check if attr_reader define the given attribute
|
164
|
+
#
|
165
|
+
# @since 0.5.1
|
166
|
+
# @api private
|
167
|
+
def allowed_attribute_name?(name)
|
168
|
+
!instance_methods.include?(name)
|
169
|
+
end
|
170
|
+
|
171
|
+
protected
|
172
|
+
|
173
|
+
# @see Class#inherited
|
174
|
+
def inherited(subclass)
|
175
|
+
subclass.attributes(*attributes)
|
176
|
+
super
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
# Defines a generic, inefficient initializer, in case that the attributes
|
181
|
+
# weren't explicitly defined with `.attributes=`.
|
182
|
+
#
|
183
|
+
# @param attributes [Hash] a set of attribute names and values
|
184
|
+
#
|
185
|
+
# @raise NoMethodError in case the given attributes are trying to set unknown
|
186
|
+
# or private methods.
|
187
|
+
#
|
188
|
+
# @since 0.1.0
|
189
|
+
#
|
190
|
+
# @see .attributes
|
191
|
+
def initialize(attributes = {})
|
192
|
+
attributes.each do |k, v|
|
193
|
+
setter = "#{ k }="
|
194
|
+
public_send(setter, v) if respond_to?(setter)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
# Overrides the equality Ruby operator
|
199
|
+
#
|
200
|
+
# Two entities are considered equal if they are instances of the same class
|
201
|
+
# and if they have the same #id.
|
202
|
+
#
|
203
|
+
# @since 0.1.0
|
204
|
+
def ==(other)
|
205
|
+
self.class == other.class &&
|
206
|
+
self.id == other.id
|
207
|
+
end
|
208
|
+
|
209
|
+
# Return the hash of attributes
|
210
|
+
#
|
211
|
+
# @since 0.2.0
|
212
|
+
#
|
213
|
+
# @example
|
214
|
+
# require 'hanami/model'
|
215
|
+
# class User
|
216
|
+
# include Hanami::Entity
|
217
|
+
# attributes :name
|
218
|
+
# end
|
219
|
+
#
|
220
|
+
# user = User.new(id: 23, name: 'Luca')
|
221
|
+
# user.to_h # => { :id => 23, :name => "Luca" }
|
222
|
+
def to_h
|
223
|
+
Hash[attribute_names.map { |a| [a, read_attribute(a)] }]
|
224
|
+
end
|
225
|
+
|
226
|
+
# Return the set of attribute names
|
227
|
+
#
|
228
|
+
# @since 0.5.1
|
229
|
+
#
|
230
|
+
# @example
|
231
|
+
# require 'hanami/model'
|
232
|
+
# class User
|
233
|
+
# include Hanami::Entity
|
234
|
+
# attributes :name
|
235
|
+
# end
|
236
|
+
#
|
237
|
+
# user = User.new(id: 23, name: 'Luca')
|
238
|
+
# user.attribute_names # #<Set: {:id, :name}>
|
239
|
+
def attribute_names
|
240
|
+
self.class.attributes
|
241
|
+
end
|
242
|
+
|
243
|
+
# Return the contents of the entity as a nicely formatted string.
|
244
|
+
#
|
245
|
+
# Display all attributes of the entity for inspection (even if they are nil)
|
246
|
+
#
|
247
|
+
# @since 0.5.1
|
248
|
+
#
|
249
|
+
# @example
|
250
|
+
# require 'hanami/model'
|
251
|
+
# class User
|
252
|
+
# include Hanami::Entity
|
253
|
+
# attributes :name, :email
|
254
|
+
# end
|
255
|
+
#
|
256
|
+
# user = User.new(id: 23, name: 'Luca')
|
257
|
+
# user.inspect # #<User:0x007fa7eefe0b58 @id=nil @name="Luca" @email=nil>
|
258
|
+
def inspect
|
259
|
+
attr_list = attribute_names.inject([]) do |res, name|
|
260
|
+
res << "@#{name}=#{read_attribute(name).inspect}"
|
261
|
+
end.join(' ')
|
262
|
+
|
263
|
+
"#<#{self.class.name}:0x00#{(__id__ << 1).to_s(16)} #{attr_list}>"
|
264
|
+
end
|
265
|
+
|
266
|
+
alias_method :to_s, :inspect
|
267
|
+
|
268
|
+
# Set attributes for entity
|
269
|
+
#
|
270
|
+
# @since 0.2.0
|
271
|
+
#
|
272
|
+
# @example
|
273
|
+
# require 'hanami/model'
|
274
|
+
# class User
|
275
|
+
# include Hanami::Entity
|
276
|
+
# attributes :name
|
277
|
+
# end
|
278
|
+
#
|
279
|
+
# user = User.new(name: 'Lucca')
|
280
|
+
# user.update(name: 'Luca')
|
281
|
+
# user.name # => 'Luca'
|
282
|
+
def update(attributes={})
|
283
|
+
attributes.each do |attribute, value|
|
284
|
+
public_send("#{attribute}=", value)
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
private
|
289
|
+
|
290
|
+
# Return the value by attribute name
|
291
|
+
#
|
292
|
+
# @since 0.5.1
|
293
|
+
# @api private
|
294
|
+
def read_attribute(attr_name)
|
295
|
+
public_send(attr_name)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Hanami
|
2
|
+
module Entity
|
3
|
+
# Dirty tracking for entities
|
4
|
+
#
|
5
|
+
# @since 0.3.1
|
6
|
+
#
|
7
|
+
# @example Dirty tracking
|
8
|
+
# require 'hanami/model'
|
9
|
+
#
|
10
|
+
# class User
|
11
|
+
# include Hanami::Entity
|
12
|
+
# include Hanami::Entity::DirtyTracking
|
13
|
+
#
|
14
|
+
# attributes :name
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# article = Article.new(title: 'Generation P')
|
18
|
+
# article.changed? # => false
|
19
|
+
#
|
20
|
+
# article.title = 'Master and Margarita'
|
21
|
+
# article.changed? # => true
|
22
|
+
#
|
23
|
+
# article.changed_attributes # => {:title => "Generation P"}
|
24
|
+
module DirtyTracking
|
25
|
+
# Override initialize process.
|
26
|
+
#
|
27
|
+
# @param attributes [Hash] a set of attribute names and values
|
28
|
+
#
|
29
|
+
# @since 0.3.1
|
30
|
+
#
|
31
|
+
# @see Hanami::Entity#initialize
|
32
|
+
def initialize(attributes = {})
|
33
|
+
super
|
34
|
+
@_initial_state = Utils::Hash.new(to_h).deep_dup
|
35
|
+
end
|
36
|
+
|
37
|
+
# Getter for hash of changed attributes.
|
38
|
+
# Return empty hash, if there is no changes
|
39
|
+
# Getter for hash of changed attributes. Value in it is the previous one.
|
40
|
+
#
|
41
|
+
# @return [::Hash] the changed attributes
|
42
|
+
#
|
43
|
+
# @since 0.3.1
|
44
|
+
#
|
45
|
+
# @example
|
46
|
+
# require 'hanami/model'
|
47
|
+
#
|
48
|
+
# class Article
|
49
|
+
# include Hanami::Entity
|
50
|
+
# include Hanami::Entity::DirtyTracking
|
51
|
+
#
|
52
|
+
# attributes :title
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# article = Article.new(title: 'The crime and punishment')
|
56
|
+
# article.changed_attributes # => {}
|
57
|
+
#
|
58
|
+
# article.title = 'Master and Margarita'
|
59
|
+
# article.changed_attributes # => {:title => "The crime and punishment"}
|
60
|
+
def changed_attributes
|
61
|
+
Hash[@_initial_state.to_a - to_h.to_a]
|
62
|
+
end
|
63
|
+
|
64
|
+
# Checks if the attributes were changed
|
65
|
+
#
|
66
|
+
# @return [TrueClass, FalseClass] the result of the check
|
67
|
+
#
|
68
|
+
# @since 0.3.1
|
69
|
+
def changed?
|
70
|
+
changed_attributes.any?
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/hanami/model.rb
CHANGED
@@ -1,7 +1,209 @@
|
|
1
|
-
require
|
1
|
+
require 'hanami/model/version'
|
2
|
+
require 'hanami/entity'
|
3
|
+
require 'hanami/entity/dirty_tracking'
|
4
|
+
require 'hanami/repository'
|
5
|
+
require 'hanami/model/mapper'
|
6
|
+
require 'hanami/model/configuration'
|
7
|
+
require 'hanami/model/error'
|
2
8
|
|
3
9
|
module Hanami
|
10
|
+
# Model
|
11
|
+
#
|
12
|
+
# @since 0.1.0
|
4
13
|
module Model
|
5
|
-
#
|
14
|
+
# Error for non persisted entity
|
15
|
+
# It's raised when we try to update or delete a non persisted entity.
|
16
|
+
#
|
17
|
+
# @since 0.1.0
|
18
|
+
#
|
19
|
+
# @see Hanami::Repository.update
|
20
|
+
class NonPersistedEntityError < Hanami::Model::Error
|
21
|
+
end
|
22
|
+
|
23
|
+
# Error for invalid mapper configuration
|
24
|
+
# It's raised when mapping is not configured correctly
|
25
|
+
#
|
26
|
+
# @since 0.2.0
|
27
|
+
#
|
28
|
+
# @see Hanami::Configuration#mapping
|
29
|
+
class InvalidMappingError < Hanami::Model::Error
|
30
|
+
end
|
31
|
+
|
32
|
+
# Error for invalid raw command syntax
|
33
|
+
#
|
34
|
+
# @since 0.5.0
|
35
|
+
class InvalidCommandError < Hanami::Model::Error
|
36
|
+
def initialize(message = "Invalid command")
|
37
|
+
super
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Error for invalid raw query syntax
|
42
|
+
#
|
43
|
+
# @since 0.3.1
|
44
|
+
class InvalidQueryError < Hanami::Model::Error
|
45
|
+
def initialize(message = "Invalid query")
|
46
|
+
super
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
include Utils::ClassAttribute
|
51
|
+
|
52
|
+
# Framework configuration
|
53
|
+
#
|
54
|
+
# @since 0.2.0
|
55
|
+
# @api private
|
56
|
+
class_attribute :configuration
|
57
|
+
self.configuration = Configuration.new
|
58
|
+
|
59
|
+
# Configure the framework.
|
60
|
+
# It yields the given block in the context of the configuration
|
61
|
+
#
|
62
|
+
# @param blk [Proc] the configuration block
|
63
|
+
#
|
64
|
+
# @since 0.2.0
|
65
|
+
#
|
66
|
+
# @see Hanami::Model
|
67
|
+
#
|
68
|
+
# @example
|
69
|
+
# require 'hanami/model'
|
70
|
+
#
|
71
|
+
# Hanami::Model.configure do
|
72
|
+
# adapter type: :sql, uri: 'postgres://localhost/database'
|
73
|
+
#
|
74
|
+
# mapping do
|
75
|
+
# collection :users do
|
76
|
+
# entity User
|
77
|
+
#
|
78
|
+
# attribute :id, Integer
|
79
|
+
# attribute :name, String
|
80
|
+
# end
|
81
|
+
# end
|
82
|
+
# end
|
83
|
+
#
|
84
|
+
# Adapter MUST follow the convention in which adapter class is inflection of adapter name
|
85
|
+
# The above example has name :sql, thus derived class will be `Hanami::Model::Adapters::SqlAdapter`
|
86
|
+
def self.configure(&blk)
|
87
|
+
configuration.instance_eval(&blk)
|
88
|
+
self
|
89
|
+
end
|
90
|
+
|
91
|
+
# Load the framework
|
92
|
+
#
|
93
|
+
# @since 0.2.0
|
94
|
+
# @api private
|
95
|
+
def self.load!
|
96
|
+
configuration.load!
|
97
|
+
end
|
98
|
+
|
99
|
+
# Unload the framework
|
100
|
+
#
|
101
|
+
# @since 0.2.0
|
102
|
+
# @api private
|
103
|
+
def self.unload!
|
104
|
+
configuration.unload!
|
105
|
+
end
|
106
|
+
|
107
|
+
# Duplicate Hanami::Model in order to create a new separated instance
|
108
|
+
# of the framework.
|
109
|
+
#
|
110
|
+
# The new instance of the framework will be completely decoupled from the
|
111
|
+
# original. It will inherit the configuration, but all the changes that
|
112
|
+
# happen after the duplication, won't be reflected on the other copies.
|
113
|
+
#
|
114
|
+
# @return [Module] a copy of Hanami::Model
|
115
|
+
#
|
116
|
+
# @since 0.2.0
|
117
|
+
# @api private
|
118
|
+
#
|
119
|
+
# @example Basic usage
|
120
|
+
# require 'hanami/model'
|
121
|
+
#
|
122
|
+
# module MyApp
|
123
|
+
# Model = Hanami::Model.dupe
|
124
|
+
# end
|
125
|
+
#
|
126
|
+
# MyApp::Model == Hanami::Model # => false
|
127
|
+
#
|
128
|
+
# MyApp::Model.configuration ==
|
129
|
+
# Hanami::Model.configuration # => false
|
130
|
+
#
|
131
|
+
# @example Inheriting configuration
|
132
|
+
# require 'hanami/model'
|
133
|
+
#
|
134
|
+
# Hanami::Model.configure do
|
135
|
+
# adapter type: :sql, uri: 'sqlite3://uri'
|
136
|
+
# end
|
137
|
+
#
|
138
|
+
# module MyApp
|
139
|
+
# Model = Hanami::Model.dupe
|
140
|
+
# end
|
141
|
+
#
|
142
|
+
# module MyApi
|
143
|
+
# Model = Hanami::Model.dupe
|
144
|
+
# Model.configure do
|
145
|
+
# adapter type: :sql, uri: 'postgresql://uri'
|
146
|
+
# end
|
147
|
+
# end
|
148
|
+
#
|
149
|
+
# Hanami::Model.configuration.adapter_config.uri # => 'sqlite3://uri'
|
150
|
+
# MyApp::Model.configuration.adapter_config.uri # => 'sqlite3://uri'
|
151
|
+
# MyApi::Model.configuration.adapter_config.uri # => 'postgresql://uri'
|
152
|
+
def self.dupe
|
153
|
+
dup.tap do |duplicated|
|
154
|
+
duplicated.configuration = Configuration.new
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# Duplicate the framework and generate modules for the target application
|
159
|
+
#
|
160
|
+
# @param mod [Module] the Ruby namespace of the application
|
161
|
+
# @param blk [Proc] an optional block to configure the framework
|
162
|
+
#
|
163
|
+
# @return [Module] a copy of Hanami::Model
|
164
|
+
#
|
165
|
+
# @since 0.2.0
|
166
|
+
#
|
167
|
+
# @see Hanami::Model#dupe
|
168
|
+
# @see Hanami::Model::Configuration
|
169
|
+
#
|
170
|
+
# @example Basic usage
|
171
|
+
# require 'hanami/model'
|
172
|
+
#
|
173
|
+
# module MyApp
|
174
|
+
# Model = Hanami::Model.dupe
|
175
|
+
# end
|
176
|
+
#
|
177
|
+
# # It will:
|
178
|
+
# #
|
179
|
+
# # 1. Generate MyApp::Model
|
180
|
+
# # 2. Generate MyApp::Entity
|
181
|
+
# # 3. Generate MyApp::Repository
|
182
|
+
#
|
183
|
+
# MyApp::Model == Hanami::Model # => false
|
184
|
+
# MyApp::Repository == Hanami::Repository # => false
|
185
|
+
#
|
186
|
+
# @example Block usage
|
187
|
+
# require 'hanami/model'
|
188
|
+
#
|
189
|
+
# module MyApp
|
190
|
+
# Model = Hanami::Model.duplicate(self) do
|
191
|
+
# adapter type: :memory, uri: 'memory://localhost'
|
192
|
+
# end
|
193
|
+
# end
|
194
|
+
#
|
195
|
+
# Hanami::Model.configuration.adapter_config # => nil
|
196
|
+
# MyApp::Model.configuration.adapter_config # => #<Hanami::Model::Config::Adapter:0x007ff0ff0244f8 @type=:memory, @uri="memory://localhost", @class_name="MemoryAdapter">
|
197
|
+
def self.duplicate(mod, &blk)
|
198
|
+
dupe.tap do |duplicated|
|
199
|
+
mod.module_eval %{
|
200
|
+
Entity = Hanami::Entity.dup
|
201
|
+
Repository = Hanami::Repository.dup
|
202
|
+
}
|
203
|
+
|
204
|
+
duplicated.configure(&blk) if block_given?
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
6
208
|
end
|
7
209
|
end
|