supa 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +11 -8
- data/.rubocop.yml +1011 -1197
- data/.travis.yml +4 -12
- data/Gemfile +1 -0
- data/README.md +65 -89
- data/Rakefile +11 -3
- data/bin/console +4 -4
- data/lib/supa.rb +1 -7
- data/lib/supa/builder.rb +24 -14
- data/lib/supa/command.rb +33 -25
- data/lib/supa/commands/append.rb +17 -0
- data/lib/supa/commands/attribute.rb +3 -1
- data/lib/supa/commands/collection.rb +6 -6
- data/lib/supa/commands/namespace.rb +6 -2
- data/lib/supa/commands/object.rb +4 -2
- data/lib/supa/commands/virtual.rb +11 -0
- data/lib/supa/representable.rb +5 -1
- data/lib/supa/version.rb +1 -1
- data/supa.gemspec +15 -22
- metadata +10 -71
- data/.reek +0 -128
- data/.rspec +0 -2
- data/lib/supa/commands/traits/collectionable.rb +0 -12
data/.travis.yml
CHANGED
@@ -2,19 +2,11 @@ sudo: false
|
|
2
2
|
language: ruby
|
3
3
|
rvm:
|
4
4
|
- 2.3.1
|
5
|
-
|
6
|
-
notifications:
|
7
|
-
email: false
|
8
|
-
|
5
|
+
before_install: gem install bundler -v 1.13.1
|
9
6
|
addons:
|
10
7
|
code_climate:
|
11
|
-
repo_token:
|
12
|
-
|
13
|
-
cache:
|
14
|
-
- bundler
|
15
|
-
|
16
|
-
before_install: gem install bundler -v 1.13.7
|
17
|
-
script:
|
18
|
-
- bundle exec rake
|
8
|
+
repo_token: eb758a7a8b04369f929aa1b962bc9764b6517539971b785600065cf5ad93e282
|
19
9
|
after_success:
|
20
10
|
- bundle exec codeclimate-test-reporter
|
11
|
+
notifications:
|
12
|
+
email: false
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -2,10 +2,10 @@
|
|
2
2
|
|
3
3
|
Ruby object → JSON serialization.
|
4
4
|
|
5
|
-
[![Build Status](https://travis-ci.org/
|
6
|
-
[![Code Climate](https://codeclimate.com/
|
7
|
-
[![Test Coverage](https://codeclimate.com/
|
8
|
-
[![Issue Count](https://codeclimate.com/
|
5
|
+
[![Build Status](https://travis-ci.org/dasnotme/supa.svg?branch=master)](https://travis-ci.org/dasnotme/supa)
|
6
|
+
[![Code Climate](https://codeclimate.com/github/dasnotme/supa/badges/gpa.svg)](https://codeclimate.com/github/dasnotme/supa)
|
7
|
+
[![Test Coverage](https://codeclimate.com/github/dasnotme/supa/badges/coverage.svg)](https://codeclimate.com/github/dasnotme/supa/coverage)
|
8
|
+
[![Issue Count](https://codeclimate.com/github/dasnotme/supa/badges/issue_count.svg)](https://codeclimate.com/github/dasnotme/supa)
|
9
9
|
|
10
10
|
## Introduction
|
11
11
|
|
@@ -49,60 +49,75 @@ end
|
|
49
49
|
```
|
50
50
|
|
51
51
|
```ruby
|
52
|
-
|
53
|
-
|
52
|
+
module Supa
|
53
|
+
class ArticleRepresenter
|
54
|
+
include Supa::Representable
|
54
55
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
namespace :data do
|
61
|
-
attribute :id
|
62
|
-
attribute :type, getter: proc { 'articles' }
|
56
|
+
define do
|
57
|
+
namespace :jsonapi do
|
58
|
+
virtual :version, 1.1, modifier: :to_s
|
59
|
+
end
|
63
60
|
|
64
|
-
namespace :
|
65
|
-
attribute :
|
66
|
-
attribute :text
|
61
|
+
namespace :meta do
|
62
|
+
attribute :locale, :language, exec_context: :representer
|
67
63
|
end
|
68
64
|
|
69
|
-
namespace :
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
65
|
+
namespace :data do
|
66
|
+
attribute :id
|
67
|
+
virtual :type, 'articles'
|
68
|
+
|
69
|
+
namespace :attributes do
|
70
|
+
attribute :title
|
71
|
+
attribute :text
|
75
72
|
end
|
76
73
|
|
77
|
-
namespace :
|
78
|
-
|
79
|
-
|
80
|
-
|
74
|
+
namespace :relationships do
|
75
|
+
object :author do
|
76
|
+
namespace :data do
|
77
|
+
attribute :id
|
78
|
+
virtual :type, 'authors'
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
namespace :comments do
|
83
|
+
collection :data, :comments do
|
84
|
+
attribute :id
|
85
|
+
virtual :type, 'comments'
|
86
|
+
end
|
81
87
|
end
|
82
88
|
end
|
83
89
|
end
|
84
|
-
end
|
85
90
|
|
86
|
-
|
87
|
-
|
88
|
-
|
91
|
+
collection :included, :author do
|
92
|
+
attribute :id
|
93
|
+
virtual :type, 'authors'
|
89
94
|
|
90
|
-
|
91
|
-
|
92
|
-
|
95
|
+
namespace :attributes do
|
96
|
+
attribute :first_name
|
97
|
+
attribute :last_name
|
98
|
+
end
|
93
99
|
end
|
94
|
-
end
|
95
100
|
|
96
|
-
|
97
|
-
|
98
|
-
|
101
|
+
append :included, :comments do
|
102
|
+
attribute :id
|
103
|
+
virtual :type, 'comments'
|
99
104
|
|
100
|
-
|
101
|
-
|
105
|
+
namespace :attributes do
|
106
|
+
attribute :text
|
107
|
+
end
|
102
108
|
end
|
103
109
|
end
|
110
|
+
|
111
|
+
def to_s(value)
|
112
|
+
value.to_s
|
113
|
+
end
|
114
|
+
|
115
|
+
def language
|
116
|
+
'en'
|
117
|
+
end
|
104
118
|
end
|
105
119
|
end
|
120
|
+
|
106
121
|
```
|
107
122
|
|
108
123
|
```ruby
|
@@ -112,7 +127,10 @@ ArticleRepresenter.new(Article.new).to_json
|
|
112
127
|
```json
|
113
128
|
{
|
114
129
|
"jsonapi": {
|
115
|
-
"version": 1.1
|
130
|
+
"version": "1.1"
|
131
|
+
},
|
132
|
+
"meta": {
|
133
|
+
"locale": "en"
|
116
134
|
},
|
117
135
|
"data": {
|
118
136
|
"id": "7aa15512-1f9d-4a86-98ad-4bb0aae487a2",
|
@@ -171,58 +189,15 @@ ArticleRepresenter.new(Article.new).to_json
|
|
171
189
|
|
172
190
|
### `attribute`
|
173
191
|
|
192
|
+
### `virtual`
|
193
|
+
|
174
194
|
### `namespace`
|
175
195
|
|
176
196
|
### `object`
|
177
197
|
|
178
198
|
### `collection`
|
179
199
|
|
180
|
-
|
181
|
-
|
182
|
-
Passing `true` to `:squash` option results in merging collection with the previous one
|
183
|
-
|
184
|
-
```ruby
|
185
|
-
class AnimalsRepresenter
|
186
|
-
include Supa::Representable
|
187
|
-
|
188
|
-
define do
|
189
|
-
collection :animals, getter: -> { [{name: 'Rex', type: 'dogs'}] } do
|
190
|
-
attribute :name
|
191
|
-
attribute :type
|
192
|
-
end
|
193
|
-
|
194
|
-
collection :animals, getter: -> { [{name: 'Tom', type: 'cats'}] }, squash: true do
|
195
|
-
attribute :name
|
196
|
-
attribute :type
|
197
|
-
end
|
198
|
-
end
|
199
|
-
end
|
200
|
-
```
|
201
|
-
|
202
|
-
```ruby
|
203
|
-
AnimalsRepresenter.new(nil).to_hash
|
204
|
-
```
|
205
|
-
|
206
|
-
```ruby
|
207
|
-
{
|
208
|
-
animals: [
|
209
|
-
{name: 'Rex', type: 'dogs'},
|
210
|
-
{name: 'Tom', type: 'cats'}
|
211
|
-
]
|
212
|
-
}
|
213
|
-
```
|
214
|
-
|
215
|
-
### `:getter` option
|
216
|
-
|
217
|
-
Avoid passing Proc objects to `:getter` option because this is little slower than method name passing
|
218
|
-
|
219
|
-
```ruby
|
220
|
-
# Bad
|
221
|
-
attribute :name, getter: -> { fetch_name }
|
222
|
-
|
223
|
-
# Good
|
224
|
-
attribute :name, getter: :fetch_name
|
225
|
-
```
|
200
|
+
### `append`
|
226
201
|
|
227
202
|
## Development
|
228
203
|
|
@@ -248,9 +223,10 @@ bin/console
|
|
248
223
|
|
249
224
|
## Contributing
|
250
225
|
|
251
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
252
|
-
|
226
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/dasnotme/supa. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
227
|
+
|
253
228
|
|
254
229
|
## License
|
255
230
|
|
256
231
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
232
|
+
|
data/Rakefile
CHANGED
@@ -1,6 +1,14 @@
|
|
1
1
|
require 'bundler/gem_tasks'
|
2
|
-
require '
|
2
|
+
require 'rake/testtask'
|
3
3
|
|
4
|
-
|
4
|
+
Rake::TestTask.new(:test) do |t|
|
5
|
+
t.libs << %w(spec lib)
|
6
|
+
t.test_files = FileList['spec/**/*_spec.rb']
|
7
|
+
end
|
5
8
|
|
6
|
-
|
9
|
+
Rake::TestTask.new(:bench) do |t|
|
10
|
+
t.libs << %w(spec lib)
|
11
|
+
t.test_files = FileList['spec/benchmarks/**/*_bench.rb']
|
12
|
+
end
|
13
|
+
|
14
|
+
task :default => :test
|
data/bin/console
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "bundler/setup"
|
4
|
+
require "supa"
|
5
5
|
|
6
6
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
7
|
# with your gem easier. You can also use a different console, if you like.
|
@@ -10,5 +10,5 @@ require 'supa'
|
|
10
10
|
# require "pry"
|
11
11
|
# Pry.start
|
12
12
|
|
13
|
-
require
|
14
|
-
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/lib/supa.rb
CHANGED
@@ -1,12 +1,6 @@
|
|
1
1
|
require 'supa/version'
|
2
|
-
require 'supa/representable'
|
3
|
-
require 'supa/command'
|
4
|
-
require 'supa/commands/traits/collectionable'
|
5
|
-
require 'supa/commands/attribute'
|
6
|
-
require 'supa/commands/object'
|
7
|
-
require 'supa/commands/namespace'
|
8
|
-
require 'supa/commands/collection'
|
9
2
|
require 'supa/builder'
|
3
|
+
require 'supa/representable'
|
10
4
|
|
11
5
|
module Supa
|
12
6
|
end
|
data/lib/supa/builder.rb
CHANGED
@@ -1,34 +1,44 @@
|
|
1
|
+
require 'supa/commands/attribute'
|
2
|
+
require 'supa/commands/virtual'
|
3
|
+
require 'supa/commands/object'
|
4
|
+
require 'supa/commands/namespace'
|
5
|
+
require 'supa/commands/collection'
|
6
|
+
require 'supa/commands/append'
|
7
|
+
|
1
8
|
module Supa
|
2
9
|
class Builder
|
3
|
-
COMMANDS = %w(attribute object namespace collection).freeze
|
10
|
+
COMMANDS = %w(attribute virtual object namespace collection append).freeze
|
4
11
|
|
5
12
|
COMMANDS.each do |command|
|
6
13
|
klass = Supa::Commands.const_get(command.capitalize)
|
7
14
|
|
8
|
-
define_method command do |name, options = {}, &block|
|
9
|
-
klass.new(
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
).represent
|
15
|
+
define_method command do |name, getter = nil, options = {}, &block|
|
16
|
+
klass.new(representer: representer,
|
17
|
+
context: context,
|
18
|
+
tree: tree,
|
19
|
+
name: name,
|
20
|
+
getter: getter,
|
21
|
+
options: options,
|
22
|
+
&block).represent
|
17
23
|
end
|
18
24
|
end
|
19
25
|
|
20
|
-
def initialize(
|
21
|
-
@object = object
|
22
|
-
@tree = tree
|
26
|
+
def initialize(representer:, context:, tree:)
|
23
27
|
@representer = representer
|
28
|
+
@context = context
|
29
|
+
@tree = tree
|
24
30
|
end
|
25
31
|
|
26
32
|
def to_hash
|
27
|
-
|
33
|
+
tree.to_hash
|
28
34
|
end
|
29
35
|
|
30
36
|
def to_json
|
31
37
|
to_hash.to_json
|
32
38
|
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
attr_reader :representer, :context, :tree
|
33
43
|
end
|
34
44
|
end
|
data/lib/supa/command.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
module Supa
|
2
2
|
class Command
|
3
|
-
def initialize(
|
4
|
-
@object = object
|
5
|
-
@tree = tree
|
3
|
+
def initialize(representer:, context:, tree:, name:, getter:, options: {}, &block)
|
6
4
|
@representer = representer
|
5
|
+
@context = context
|
6
|
+
@tree = tree
|
7
7
|
@name = name
|
8
|
+
@getter = getter
|
8
9
|
@options = options
|
9
10
|
@block = block
|
10
11
|
end
|
@@ -14,43 +15,50 @@ module Supa
|
|
14
15
|
end
|
15
16
|
|
16
17
|
private
|
18
|
+
attr_reader :representer, :context, :tree, :name, :options, :block
|
17
19
|
|
18
|
-
def value
|
19
|
-
|
20
|
+
def apply_modifier(value)
|
21
|
+
with_modifier? ? representer.send(modifier, value) : value
|
22
|
+
end
|
20
23
|
|
21
|
-
|
22
|
-
|
24
|
+
def modifier
|
25
|
+
options[:modifier]
|
26
|
+
end
|
23
27
|
|
24
|
-
|
25
|
-
|
28
|
+
def with_modifier?
|
29
|
+
!!options[:modifier]
|
26
30
|
end
|
27
31
|
|
28
|
-
def
|
29
|
-
|
32
|
+
def static_value
|
33
|
+
value = getter
|
34
|
+
|
35
|
+
apply_modifier(value)
|
30
36
|
end
|
31
37
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
38
|
+
def dynamic_value
|
39
|
+
value = if exec_on_object?
|
40
|
+
value_from_object
|
41
|
+
else
|
42
|
+
value_from_representer
|
37
43
|
end
|
44
|
+
|
45
|
+
apply_modifier(value)
|
38
46
|
end
|
39
47
|
|
40
|
-
def
|
41
|
-
|
42
|
-
value_accessor unless value_accessor.is_a?(Symbol) || value_accessor.is_a?(Enumerable)
|
48
|
+
def exec_on_object?
|
49
|
+
options[:exec_context] != :representer
|
43
50
|
end
|
44
51
|
|
45
|
-
def
|
46
|
-
|
52
|
+
def value_from_object
|
53
|
+
context.is_a?(Hash) ? context[getter] : context.send(getter)
|
47
54
|
end
|
48
55
|
|
49
|
-
def
|
50
|
-
|
51
|
-
|
56
|
+
def value_from_representer
|
57
|
+
representer.send(getter)
|
58
|
+
end
|
52
59
|
|
53
|
-
|
60
|
+
def getter
|
61
|
+
@getter || @name
|
54
62
|
end
|
55
63
|
end
|
56
64
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'supa/command'
|
2
|
+
|
3
|
+
module Supa
|
4
|
+
module Commands
|
5
|
+
class Append < Supa::Command
|
6
|
+
def represent
|
7
|
+
tree[name] ||= []
|
8
|
+
|
9
|
+
Array(dynamic_value).each do |element|
|
10
|
+
tree[name] << {}
|
11
|
+
|
12
|
+
Supa::Builder.new(representer: representer, context: element, tree: tree[name][-1]).instance_exec(&block)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|