active_mappers 1.2.4 → 1.3.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/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +46 -0
- data/README.md +431 -0
- data/Rakefile +9 -0
- data/active_mappers.gemspec +20 -0
- data/lib/active_mappers.rb +19 -23
- data/lib/active_mappers/handlers/inheritance.rb +26 -0
- data/lib/active_mappers/key_transformer.rb +1 -0
- metadata +50 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2ec2a77d6b91e05de5d86ab9a43b37d5fd7245085d696ccd9c7fb5aa900a42a3
|
4
|
+
data.tar.gz: b930be8ee3ac6adf404cfe9c0bad1107b9eb3287912c347b940438f2bab95af4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9d29e59cc9231aab42657fbc2eb8c8e8106ed3a5e61752763efa3454de2775f4a7189886ebf46f626ea7b74b6d70c93bb3cf6c930dc23a77b7ffdb10cdfeaa8b
|
7
|
+
data.tar.gz: 774c84aea5e4b793ea0ce59ea8160ad2b626fe1d3d53392bc7d4909eff89c9629b7e69c1859ae8b6dc1198407f671554250430d26333d1ee8fbe26c4b657afe0
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
active_mappers (1.3.0)
|
5
|
+
activesupport (>= 4.2)
|
6
|
+
method_source (~> 0.9.2)
|
7
|
+
mocha (>= 1.8.0)
|
8
|
+
ruby2ruby (> 2.4.0)
|
9
|
+
ruby_parser (~> 3.1)
|
10
|
+
|
11
|
+
GEM
|
12
|
+
remote: https://rubygems.org/
|
13
|
+
specs:
|
14
|
+
activesupport (5.2.2)
|
15
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
16
|
+
i18n (>= 0.7, < 2)
|
17
|
+
minitest (~> 5.1)
|
18
|
+
tzinfo (~> 1.1)
|
19
|
+
concurrent-ruby (1.1.5)
|
20
|
+
i18n (1.6.0)
|
21
|
+
concurrent-ruby (~> 1.0)
|
22
|
+
metaclass (0.0.4)
|
23
|
+
method_source (0.9.2)
|
24
|
+
minitest (5.11.3)
|
25
|
+
mocha (1.8.0)
|
26
|
+
metaclass (~> 0.0.1)
|
27
|
+
rake (12.3.1)
|
28
|
+
ruby2ruby (2.4.2)
|
29
|
+
ruby_parser (~> 3.1)
|
30
|
+
sexp_processor (~> 4.6)
|
31
|
+
ruby_parser (3.13.0)
|
32
|
+
sexp_processor (~> 4.9)
|
33
|
+
sexp_processor (4.12.0)
|
34
|
+
thread_safe (0.3.6)
|
35
|
+
tzinfo (1.2.5)
|
36
|
+
thread_safe (~> 0.1)
|
37
|
+
|
38
|
+
PLATFORMS
|
39
|
+
ruby
|
40
|
+
|
41
|
+
DEPENDENCIES
|
42
|
+
active_mappers!
|
43
|
+
rake
|
44
|
+
|
45
|
+
BUNDLED WITH
|
46
|
+
1.17.2
|
data/README.md
ADDED
@@ -0,0 +1,431 @@
|
|
1
|
+
# ActiveMappers
|
2
|
+
|
3
|
+
[](https://travis-ci.org/FidMe/active_mappers)
|
4
|
+
[](https://badge.fury.io/rb/active_mappers)
|
5
|
+
|
6
|
+
If you have ever done Rails API development, you must have considered using a layer to abstract and centralize your JSON objects construction.
|
7
|
+
|
8
|
+
There are multiple solutions out on the market, here is a quick overview of each :
|
9
|
+
|
10
|
+
| Solution | Pros | Cons |
|
11
|
+
| ------------------------ | ---------------------------------------------------------------------------------- | ----------------------------------------------------- |
|
12
|
+
| JBuilder | Simple, easy, integrates with the default View layer | Very slow, dedicated to JSON |
|
13
|
+
| Active Model Serializers | Simple, easy to declare | Can be hard to customize, slow, project is abandonned |
|
14
|
+
| fast_json_api | As simple as AMS, fast | Hard to customize, JSONAPI standard is required |
|
15
|
+
| ActiveMappers | Blazing fast, Easy to declare/customize, works with any format output (JSON, Hash) | Limited number of options (for now) |
|
16
|
+
|
17
|
+
## Installation
|
18
|
+
|
19
|
+
Add this line to your application's Gemfile:
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
gem 'active_mappers'
|
23
|
+
```
|
24
|
+
|
25
|
+
Execute
|
26
|
+
|
27
|
+
```bash
|
28
|
+
$ bundle install
|
29
|
+
```
|
30
|
+
|
31
|
+
Then, depending on your usage you may want to create an `app/mappers` folder in your Rails application.
|
32
|
+
|
33
|
+
You will put all your mappers inside of it.
|
34
|
+
|
35
|
+
## Usage
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
UserMapper.with(user)
|
39
|
+
# =>
|
40
|
+
# {
|
41
|
+
# user: {
|
42
|
+
# id: '123',
|
43
|
+
# email: 'mvilleneuve@snapp.fr',
|
44
|
+
# profile: {
|
45
|
+
# first_name: 'Michael',
|
46
|
+
# last_name: 'Villeneuve',
|
47
|
+
# }
|
48
|
+
# }
|
49
|
+
# }
|
50
|
+
```
|
51
|
+
|
52
|
+
### Setup (optional)
|
53
|
+
|
54
|
+
You may want to customize some parts of ActiveMappers behavior.
|
55
|
+
|
56
|
+
If you want to, create an initializer in your project :
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
# config/initializers/active_mappers.rb
|
60
|
+
ActiveMappers::Setup.configure do |config|
|
61
|
+
config.camelcase_keys = false
|
62
|
+
config.ignored_namespaces = [:admin, :back_office]
|
63
|
+
end
|
64
|
+
```
|
65
|
+
|
66
|
+
Here is the list of configurable options
|
67
|
+
|
68
|
+
| Option | Type | Default | Description |
|
69
|
+
| ----------------------- | --------- | --------- | ------------------------------------------------------------------ |
|
70
|
+
| `camelcase_keys` | `boolean` | `true` | Should keys name be camelcase. Fallback to snake when set to false |
|
71
|
+
| `ignored_namespaces` | `Array` | `[]` | Namespaces to ignore when generating json root key name |
|
72
|
+
| `root_keys_transformer` | `Proc` | See below | Custom way to change a mapper class name into a JSON root key |
|
73
|
+
|
74
|
+
**Root Keys Transformer**
|
75
|
+
|
76
|
+
A root key transform is used to transform the mapper class name into a JSON root key name.
|
77
|
+
|
78
|
+
For example this mapper class :
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
class User::ProfileInformationMapper < ActiveMappers::Base
|
82
|
+
end
|
83
|
+
```
|
84
|
+
|
85
|
+
Will automatically resolve to the following json :
|
86
|
+
|
87
|
+
```json
|
88
|
+
{
|
89
|
+
"user/profileInformation": {}
|
90
|
+
}
|
91
|
+
```
|
92
|
+
|
93
|
+
To customize this behavior you can do the following :
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
config.root_keys_transformer = proc do |key|
|
97
|
+
# Return any key transform based on the key which is the class name of your mapper
|
98
|
+
|
99
|
+
# The below line transforms User::ProfileInformationMapper to user/profile_informations
|
100
|
+
key.gsub('Mapper', '').tableize
|
101
|
+
end
|
102
|
+
```
|
103
|
+
|
104
|
+
### Creating a mapper
|
105
|
+
|
106
|
+
**Declaring your attributes**
|
107
|
+
|
108
|
+
Most basic usage, just declare the attributes you want to display.
|
109
|
+
|
110
|
+
```ruby
|
111
|
+
class UserMapper < ActiveMappers::Base # You must extend ActiveMappers::Base in order to use the DSL
|
112
|
+
attributes :id, :email
|
113
|
+
end
|
114
|
+
```
|
115
|
+
|
116
|
+
**Delegating your attributes**
|
117
|
+
|
118
|
+
Say you have a model with the following structure :
|
119
|
+
|
120
|
+
```ruby
|
121
|
+
{
|
122
|
+
email: 'mvilleneuve@snapp.fr',
|
123
|
+
profile: {
|
124
|
+
first_name: 'Michael',
|
125
|
+
}
|
126
|
+
}
|
127
|
+
```
|
128
|
+
|
129
|
+
And you want to generate this structure :
|
130
|
+
|
131
|
+
```ruby
|
132
|
+
{
|
133
|
+
email: 'mvilleneuve@snapp.fr',
|
134
|
+
first_name: 'Michael',
|
135
|
+
last_name: 'Villeneuve',
|
136
|
+
}
|
137
|
+
```
|
138
|
+
|
139
|
+
To implement this, you must use the `delegate` feature :
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
class UserMapper < ActiveMappers::Base
|
143
|
+
delegate :first_name, :last_name, to: :profile
|
144
|
+
end
|
145
|
+
```
|
146
|
+
|
147
|
+
**Declaring relationship**
|
148
|
+
|
149
|
+
You can declare any type of relationship (`has_one`, `belongs_to`, `has_many`, etc) and the mapper that matches it will automatically be fetched and used.
|
150
|
+
|
151
|
+
For example if a `User` has a `belongs_to` relationship with an `Account` you can write :
|
152
|
+
|
153
|
+
```ruby
|
154
|
+
class UserMapper < ActiveMappers::Base
|
155
|
+
attributes :email
|
156
|
+
relation :account # Will automatically resolve to AccountMapper
|
157
|
+
end
|
158
|
+
|
159
|
+
class AccountMapper < ActiveMappers::Base
|
160
|
+
attributes :first_name, :last_name
|
161
|
+
end
|
162
|
+
```
|
163
|
+
|
164
|
+
It will generate something like
|
165
|
+
|
166
|
+
```ruby
|
167
|
+
{
|
168
|
+
user: {
|
169
|
+
email: 'mvilleneuve@snapp.fr',
|
170
|
+
account: {
|
171
|
+
first_name: 'Michael',
|
172
|
+
last_name: 'Villeneuve'
|
173
|
+
}
|
174
|
+
}
|
175
|
+
}
|
176
|
+
```
|
177
|
+
|
178
|
+
It also works with namespaced resources.
|
179
|
+
|
180
|
+
If you need you can specify more options :
|
181
|
+
|
182
|
+
```ruby
|
183
|
+
class UserMapper < ActiveMappers::Base
|
184
|
+
relation :account, AccountMapper, scope: :admin
|
185
|
+
end
|
186
|
+
|
187
|
+
|
188
|
+
|
189
|
+
**Declaring polymorphic relationships**
|
190
|
+
|
191
|
+
Consider the following polymorphic relation :
|
192
|
+
|
193
|
+
```ruby
|
194
|
+
class Post
|
195
|
+
belongs_to :author, polymorphic: true
|
196
|
+
end
|
197
|
+
|
198
|
+
class AdminUser
|
199
|
+
has_many :posts, class_name: 'Post', as: :author
|
200
|
+
end
|
201
|
+
|
202
|
+
class NormalUser
|
203
|
+
has_many :posts, class_name: 'Post', as: :author
|
204
|
+
end
|
205
|
+
```
|
206
|
+
|
207
|
+
In order to use the `author` polymorphic attribute in your `PostMapper` you need to declare the following :
|
208
|
+
|
209
|
+
```ruby
|
210
|
+
class PostMapper < ActiveMappers::Base
|
211
|
+
polymorphic :author
|
212
|
+
end
|
213
|
+
```
|
214
|
+
|
215
|
+
And of course, you must implement the associated mappers :
|
216
|
+
|
217
|
+
```ruby
|
218
|
+
class AdminUserMapper
|
219
|
+
attributes :id, :name
|
220
|
+
end
|
221
|
+
|
222
|
+
class NormalUserMapper
|
223
|
+
attributes :id, :name
|
224
|
+
end
|
225
|
+
```
|
226
|
+
|
227
|
+
Then, based of the `XXX_type` column, the mapper will automatically resolve to either `AdminUserMapper` or `NormalUserMapper`
|
228
|
+
|
229
|
+
**Rendering a collection of different classes**
|
230
|
+
|
231
|
+
Say you want to render many resources with a single Mapper
|
232
|
+
|
233
|
+
```ruby
|
234
|
+
collection = Bird.all + Fish.all + Insect.all
|
235
|
+
|
236
|
+
render json: AnimalMapper.with(collection)
|
237
|
+
|
238
|
+
class AnimalMapper < ActiveMappers::Base
|
239
|
+
acts_as_polymorphic
|
240
|
+
end
|
241
|
+
|
242
|
+
class BirdMapper < ActiveMappers::Base
|
243
|
+
attributes :name, :wings_count
|
244
|
+
end
|
245
|
+
|
246
|
+
class FishMapper < ActiveMappers::Base
|
247
|
+
attributes :name, :fins_count
|
248
|
+
end
|
249
|
+
|
250
|
+
class InsectMapper < ActiveMappers::Base
|
251
|
+
attributes :name, :has_venom
|
252
|
+
end
|
253
|
+
```
|
254
|
+
|
255
|
+
Will generate the following :
|
256
|
+
|
257
|
+
```ruby
|
258
|
+
{
|
259
|
+
animals: [
|
260
|
+
{ name: 'Michael', wings_count: 2 },
|
261
|
+
{ name: 'Emeric', fins_count: 1 },
|
262
|
+
{ name: 'Arthur', has_venom: true },
|
263
|
+
]
|
264
|
+
}
|
265
|
+
```
|
266
|
+
|
267
|
+
Again, just like the above polymorphic declaration, the mapper will automatically resolve to the corresponding one.
|
268
|
+
|
269
|
+
**Custom Attributes**
|
270
|
+
|
271
|
+
If you need to implement custom attributes you can always use the `each` statement.
|
272
|
+
|
273
|
+
```ruby
|
274
|
+
class UserMapper < ActiveMappers::Base
|
275
|
+
attributes :email, :id
|
276
|
+
|
277
|
+
each do |user|
|
278
|
+
{
|
279
|
+
custom_attribute: "Hi, I'm a custom attribute",
|
280
|
+
another_custom_attribute: Time.now
|
281
|
+
}
|
282
|
+
end
|
283
|
+
end
|
284
|
+
```
|
285
|
+
|
286
|
+
Will generate the following:
|
287
|
+
|
288
|
+
```ruby
|
289
|
+
{
|
290
|
+
user: {
|
291
|
+
id: '12345',
|
292
|
+
email: 'mvilleneuve@snapp.fr',
|
293
|
+
custom_attribute: "Hi, I'm a custom attribute",
|
294
|
+
another_custom_attribute: "2018-09-26 17:49:59 +0200"
|
295
|
+
}
|
296
|
+
}
|
297
|
+
```
|
298
|
+
|
299
|
+
You can declare any number of `each` in a single mapper.
|
300
|
+
Actually, `each` is used to implement every above features.
|
301
|
+
|
302
|
+
**Scope**
|
303
|
+
|
304
|
+
ActiveMappers does not yet support inheritance. However we provide an even better alternative named `scope`.
|
305
|
+
|
306
|
+
Whenever you feel the need to declare more or less attributes based on who called the mapper, you may want to consider using scope.
|
307
|
+
|
308
|
+
A very usual use case would be to have a different way to map a resource depending on wether you are an administrator or not.
|
309
|
+
Instead of declaring a whole new mapper just to add/remove attributes, you can do the following :
|
310
|
+
|
311
|
+
```ruby
|
312
|
+
class UserMapper < ActiveMappers::Base
|
313
|
+
attributes :pseudo
|
314
|
+
|
315
|
+
scope :admin
|
316
|
+
attributes :id
|
317
|
+
end
|
318
|
+
|
319
|
+
scope :owner
|
320
|
+
attributes :email
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
# This declaration gives you 3 ways to call the mapper
|
325
|
+
|
326
|
+
# By an administrator
|
327
|
+
UserMapper.with(User.first, scope: :admin)
|
328
|
+
# => { pseudo: 'michael33', id: '1234' }
|
329
|
+
|
330
|
+
# By anyone
|
331
|
+
UserMapper.with(User.first)
|
332
|
+
# => { pseudo: 'michael33' }
|
333
|
+
|
334
|
+
# Or by the corresponding user that will gain access to personal informations
|
335
|
+
UserMapper.with(User.first, scope: :owner)
|
336
|
+
# => { pseudo: 'michael33', email: 'mvilleneuve@fidme.com' }
|
337
|
+
```
|
338
|
+
|
339
|
+
|
340
|
+
## Using a mapper
|
341
|
+
|
342
|
+
Even though there are many ways to declare a mapper, there is only one way to use it
|
343
|
+
|
344
|
+
```ruby
|
345
|
+
UserMapper.with(User.first)
|
346
|
+
|
347
|
+
# Or use it with a collection
|
348
|
+
UserMapper.with(User.all)
|
349
|
+
```
|
350
|
+
|
351
|
+
In a Rails controller :
|
352
|
+
|
353
|
+
```ruby
|
354
|
+
def index
|
355
|
+
render json: UserMapper.with(User.all)
|
356
|
+
end
|
357
|
+
```
|
358
|
+
|
359
|
+
### JSON Root
|
360
|
+
|
361
|
+
You can choose to use ActiveMappers with or without a JSON root.
|
362
|
+
|
363
|
+
By default, root will be enabled, meaning a UserMapper, will generate a JSON prefixed by :
|
364
|
+
|
365
|
+
```ruby
|
366
|
+
{
|
367
|
+
user: {}
|
368
|
+
}
|
369
|
+
```
|
370
|
+
|
371
|
+
**Custom Root**
|
372
|
+
|
373
|
+
If you want to customize the root name, you can use
|
374
|
+
|
375
|
+
```ruby
|
376
|
+
UserMapper.with(user, root: :hello)
|
377
|
+
```
|
378
|
+
|
379
|
+
which will generate :
|
380
|
+
|
381
|
+
```ruby
|
382
|
+
{
|
383
|
+
hello: {}
|
384
|
+
}
|
385
|
+
```
|
386
|
+
|
387
|
+
**Rootless**
|
388
|
+
|
389
|
+
If you do not want to set any root, use :
|
390
|
+
|
391
|
+
```ruby
|
392
|
+
UserMapper.with(user, rootless: true)
|
393
|
+
```
|
394
|
+
|
395
|
+
## Adding your own features to Active Mapper DSL
|
396
|
+
|
397
|
+
If you want to add specific features to the DSL you can reopen `::ActiveMappers::Base` class and add your own methods.
|
398
|
+
The most convenient way to do that is in your Active Mapper initializer following this pattern:
|
399
|
+
|
400
|
+
```ruby
|
401
|
+
ActiveMappers::Setup.configure do |config|
|
402
|
+
...
|
403
|
+
end
|
404
|
+
|
405
|
+
module ActiveMappers
|
406
|
+
class Base
|
407
|
+
include Rails.application.routes.url_helpers
|
408
|
+
|
409
|
+
def self.my_capitalize_dsl_feature(*params)
|
410
|
+
each do |resource| #your mapped resource(s)
|
411
|
+
h = {}
|
412
|
+
params.each do |param|
|
413
|
+
h[param] = resource.try(param)&.capitalize #your treatment
|
414
|
+
end
|
415
|
+
h #the returned hash will be merged to the mapper result.
|
416
|
+
end
|
417
|
+
end
|
418
|
+
end
|
419
|
+
end
|
420
|
+
```
|
421
|
+
and then:
|
422
|
+
|
423
|
+
```ruby
|
424
|
+
class UserMapper < ActiveMappers::Base
|
425
|
+
my_capitalize_dsl_feature :civility
|
426
|
+
end
|
427
|
+
```
|
428
|
+
|
429
|
+
## Anything is missing ?
|
430
|
+
|
431
|
+
File an issue
|
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'active_mappers'
|
3
|
+
s.version = '1.3.0'
|
4
|
+
s.date = '2019-05-10'
|
5
|
+
s.summary = 'Slick, fast view layer for you Rails API.'
|
6
|
+
s.description = 'Fast, simple, declarative way to design your API\'s view layer'
|
7
|
+
s.authors = ['Michaël Villeneuve']
|
8
|
+
s.homepage = 'https://github.com/fidme/active_mappers'
|
9
|
+
s.email = 'contact@michaelvilleneuve.fr'
|
10
|
+
s.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
11
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
12
|
+
end
|
13
|
+
|
14
|
+
s.license = 'MIT'
|
15
|
+
s.add_runtime_dependency('activesupport', ['>= 4.2'])
|
16
|
+
s.add_runtime_dependency('method_source', ['~> 0.9.2'])
|
17
|
+
s.add_runtime_dependency('mocha', ['>= 1.8.0'])
|
18
|
+
s.add_runtime_dependency('ruby2ruby', ['> 2.4.0'])
|
19
|
+
s.add_runtime_dependency('ruby_parser', ['~> 3.1'])
|
20
|
+
end
|
data/lib/active_mappers.rb
CHANGED
@@ -1,14 +1,23 @@
|
|
1
|
+
require 'method_source'
|
2
|
+
require 'ruby2ruby'
|
3
|
+
require 'ruby_parser'
|
4
|
+
|
1
5
|
require 'active_support'
|
2
6
|
require 'active_support/core_ext/object/try'
|
7
|
+
require 'active_support/core_ext/hash/except'
|
3
8
|
require 'active_support/core_ext/string/inflections'
|
4
9
|
require_relative 'core_ext/hash'
|
10
|
+
require_relative 'active_mappers/handlers/inheritance'
|
5
11
|
require_relative 'active_mappers/key_transformer'
|
6
12
|
|
13
|
+
|
7
14
|
module ActiveMappers
|
8
15
|
class Base
|
9
16
|
@@renderers = {}
|
10
|
-
|
11
|
-
|
17
|
+
|
18
|
+
def self.inherited(subclass)
|
19
|
+
Handlers::Inheritance.new(subclass, self).handle
|
20
|
+
end
|
12
21
|
|
13
22
|
def self.attributes(*params)
|
14
23
|
each do |resource|
|
@@ -66,36 +75,28 @@ module ActiveMappers
|
|
66
75
|
end
|
67
76
|
|
68
77
|
def self.with(args, options = {})
|
69
|
-
evaluate_scopes(options[:scope]
|
70
|
-
|
78
|
+
return evaluate_scopes(args, options) unless options[:scope].nil?
|
79
|
+
|
71
80
|
response = if options[:rootless]
|
72
81
|
args.respond_to?(:each) ? all(args) : one(args)
|
73
82
|
else
|
74
83
|
render_with_root(args, options)
|
75
84
|
end
|
76
85
|
response
|
77
|
-
ensure
|
78
|
-
reset_renderers_before_scopes if !options[:scope].nil?
|
79
86
|
end
|
80
87
|
|
81
|
-
def self.evaluate_scopes(
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
found_scope = (@@scopes[name] || []).detect { |s| s[:name] === scope_name }
|
86
|
-
raise "ActiveMappers [#{name}] Scope named #{scope_name} has not been declared or is not a block" if found_scope.nil? || found_scope[:lambda].nil? || !found_scope[:lambda].respond_to?(:call)
|
87
|
-
|
88
|
-
found_scope[:lambda].call
|
88
|
+
def self.evaluate_scopes(args, options)
|
89
|
+
class_to_call = "::#{name}Scope#{options[:scope].capitalize}".constantize rescue raise("ActiveMappers [#{name}] No scope named #{options[:scope]} found")
|
90
|
+
return class_to_call.with(args, options.except(:scope))
|
89
91
|
end
|
90
92
|
|
91
93
|
def self.scope(*params, &block)
|
92
94
|
raise "ActiveMappers [#{name}] scope must be a bloc" if block.nil? || !block.respond_to?(:call)
|
93
95
|
|
96
|
+
|
94
97
|
params.each do |param|
|
95
|
-
|
96
|
-
|
97
|
-
lambda: block,
|
98
|
-
}
|
98
|
+
block_content = Ruby2Ruby.new.process(RubyParser.new.process(block.source).to_a.last)
|
99
|
+
eval("class ::#{name}Scope#{param.capitalize} < ::#{name} ; #{block_content}; end")
|
99
100
|
end
|
100
101
|
end
|
101
102
|
|
@@ -123,10 +124,5 @@ module ActiveMappers
|
|
123
124
|
|
124
125
|
KeyTransformer.format_keys(renderers)
|
125
126
|
end
|
126
|
-
|
127
|
-
def self.reset_renderers_before_scopes
|
128
|
-
return if !@@initial_renderers || !@@initial_renderers[name]
|
129
|
-
@@renderers[name] = @@initial_renderers[name].dup
|
130
|
-
end
|
131
127
|
end
|
132
128
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module ActiveMappers
|
2
|
+
module Handlers
|
3
|
+
class Inheritance
|
4
|
+
def initialize(subclass, klass)
|
5
|
+
@subclass = subclass
|
6
|
+
@klass = klass
|
7
|
+
end
|
8
|
+
|
9
|
+
def handle
|
10
|
+
return nil if regular_inheritance?
|
11
|
+
|
12
|
+
@klass.class_variables.each do |var_name|
|
13
|
+
dsl_values = @subclass.class_variable_get(var_name)
|
14
|
+
|
15
|
+
dsl_values[@subclass.name] = dsl_values[@klass.name].dup
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def regular_inheritance?
|
22
|
+
@klass == ActiveMappers::Base
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_mappers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michaël Villeneuve
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '4.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: method_source
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.9.2
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.9.2
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: mocha
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,13 +52,48 @@ dependencies:
|
|
38
52
|
- - ">="
|
39
53
|
- !ruby/object:Gem::Version
|
40
54
|
version: 1.8.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: ruby2ruby
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.4.0
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 2.4.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: ruby_parser
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.1'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.1'
|
41
83
|
description: Fast, simple, declarative way to design your API's view layer
|
42
84
|
email: contact@michaelvilleneuve.fr
|
43
85
|
executables: []
|
44
86
|
extensions: []
|
45
87
|
extra_rdoc_files: []
|
46
88
|
files:
|
89
|
+
- ".travis.yml"
|
90
|
+
- Gemfile
|
91
|
+
- Gemfile.lock
|
92
|
+
- README.md
|
93
|
+
- Rakefile
|
94
|
+
- active_mappers.gemspec
|
47
95
|
- lib/active_mappers.rb
|
96
|
+
- lib/active_mappers/handlers/inheritance.rb
|
48
97
|
- lib/active_mappers/key_transformer.rb
|
49
98
|
- lib/active_mappers/setup.rb
|
50
99
|
- lib/core_ext/hash.rb
|