supa 0.2.3 → 0.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.
data/.travis.yml CHANGED
@@ -2,11 +2,19 @@ sudo: false
2
2
  language: ruby
3
3
  rvm:
4
4
  - 2.3.1
5
- before_install: gem install bundler -v 1.13.1
5
+
6
+ notifications:
7
+ email: false
8
+
6
9
  addons:
7
10
  code_climate:
8
- repo_token: eb758a7a8b04369f929aa1b962bc9764b6517539971b785600065cf5ad93e282
11
+ repo_token: ad743cd1c267d4a84bfa620869f906a68efba51baa3aadc0638b88330ce3ab3a
12
+
13
+ cache:
14
+ - bundler
15
+
16
+ before_install: gem install bundler -v 1.13.7
17
+ script:
18
+ - bundle exec rake
9
19
  after_success:
10
20
  - bundle exec codeclimate-test-reporter
11
- notifications:
12
- email: false
data/Gemfile CHANGED
@@ -1,4 +1,3 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- # Specify your gem's dependencies in supa.gemspec
4
3
  gemspec
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/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)
5
+ [![Build Status](https://travis-ci.org/distribusion/supa.svg?branch=master)](https://travis-ci.org/distribusion/supa)
6
+ [![Code Climate](https://codeclimate.com/repos/587387071c36ea7203000e0d/badges/19b714c64bf6f028a58c/gpa.svg)](https://codeclimate.com/repos/587387071c36ea7203000e0d/feed)
7
+ [![Test Coverage](https://codeclimate.com/repos/587387071c36ea7203000e0d/badges/19b714c64bf6f028a58c/coverage.svg)](https://codeclimate.com/repos/587387071c36ea7203000e0d/coverage)
8
+ [![Issue Count](https://codeclimate.com/repos/587387071c36ea7203000e0d/badges/19b714c64bf6f028a58c/issue_count.svg)](https://codeclimate.com/repos/587387071c36ea7203000e0d/feed)
9
9
 
10
10
  ## Introduction
11
11
 
@@ -24,7 +24,7 @@ bundle install
24
24
  ```
25
25
 
26
26
  Or install it yourself as
27
- ```
27
+ ```shell
28
28
  gem install supa
29
29
  ```
30
30
 
@@ -49,75 +49,77 @@ end
49
49
  ```
50
50
 
51
51
  ```ruby
52
- module Supa
53
- class ArticleRepresenter
54
- include Supa::Representable
52
+ class ArticleRepresenter
53
+ include Supa::Representable
55
54
 
56
- define do
57
- namespace :jsonapi do
58
- virtual :version, 1.1, modifier: :to_s
59
- end
55
+ define do
56
+ namespace :jsonapi do
57
+ virtual :version, getter: 1.1, modifier: :to_s
58
+ end
60
59
 
61
- namespace :meta do
62
- attribute :locale, :language, exec_context: :representer
63
- end
60
+ namespace :meta do
61
+ attribute :locale, getter: :language, exec_context: :representer
62
+ attribute :date, exec_context: :representer
63
+ end
64
64
 
65
- namespace :data do
66
- attribute :id
67
- virtual :type, 'articles'
65
+ namespace :data do
66
+ attribute :id
67
+ virtual :type, getter: 'articles'
68
68
 
69
- namespace :attributes do
70
- attribute :title
71
- attribute :text
72
- end
69
+ namespace :attributes do
70
+ attribute :title
71
+ attribute :text
72
+ end
73
73
 
74
- namespace :relationships do
75
- object :author do
76
- namespace :data do
77
- attribute :id
78
- virtual :type, 'authors'
79
- end
74
+ namespace :relationships do
75
+ object :author do
76
+ namespace :data do
77
+ attribute :id
78
+ virtual :type, getter: 'authors'
80
79
  end
80
+ end
81
81
 
82
- namespace :comments do
83
- collection :data, :comments do
84
- attribute :id
85
- virtual :type, 'comments'
86
- end
82
+ namespace :comments do
83
+ collection :data, getter: :comments do
84
+ attribute :id
85
+ virtual :type, getter: 'comments'
87
86
  end
88
87
  end
89
88
  end
89
+ end
90
90
 
91
- collection :included, :author do
92
- attribute :id
93
- virtual :type, 'authors'
91
+ collection :included, getter: :author do
92
+ attribute :id
93
+ virtual :type, getter: 'authors'
94
94
 
95
- namespace :attributes do
96
- attribute :first_name
97
- attribute :last_name
98
- end
95
+ namespace :attributes do
96
+ attribute :first_name
97
+ attribute :last_name
99
98
  end
99
+ end
100
100
 
101
- append :included, :comments do
102
- attribute :id
103
- virtual :type, 'comments'
101
+ append :included, getter: :comments do
102
+ attribute :id
103
+ virtual :type, getter: 'comments'
104
104
 
105
- namespace :attributes do
106
- attribute :text
107
- end
105
+ namespace :attributes do
106
+ attribute :text
108
107
  end
109
108
  end
109
+ end
110
110
 
111
- def to_s(value)
112
- value.to_s
113
- end
111
+ def to_s(value)
112
+ value.to_s
113
+ end
114
114
 
115
- def language
116
- 'en'
117
- end
115
+ def language
116
+ 'en'
118
117
  end
119
- end
120
118
 
119
+ def date
120
+ Date.today.iso8601
121
+ end
122
+ end
121
123
  ```
122
124
 
123
125
  ```ruby
@@ -130,7 +132,8 @@ ArticleRepresenter.new(Article.new).to_json
130
132
  "version": "1.1"
131
133
  },
132
134
  "meta": {
133
- "locale": "en"
135
+ "locale": "en",
136
+ "date": "2050-01-01"
134
137
  },
135
138
  "data": {
136
139
  "id": "7aa15512-1f9d-4a86-98ad-4bb0aae487a2",
@@ -188,9 +191,92 @@ ArticleRepresenter.new(Article.new).to_json
188
191
  ```
189
192
 
190
193
  ### `attribute`
194
+ Attributes will be retrieved from correspondingly named instance methods unless a getter is defined:
195
+ ```ruby
196
+ class ExampleRepresenter
197
+ include Supa::Representable
198
+
199
+ define do
200
+ attribute :name
201
+ end
202
+ end
203
+
204
+ ExampleRepresenter.new(OpenStruct.new(name: 'Heidi')).to_hash
205
+
206
+ #=> {
207
+ #=> name: 'Heidi'
208
+ #=> }
209
+ ```
210
+ A getter can take several forms:
211
+
212
+ ### 1. Method name
213
+ ```ruby
214
+ class ExampleRepresenter
215
+ include Supa::Representable
216
+
217
+ define do
218
+ attribute :name, getter: :full_name
219
+ end
220
+ end
221
+
222
+ class Person
223
+ attr_accessor :full_name
224
+ end
225
+
226
+ example = Person.new
227
+ example.full_name = 'Heidi Shepherd'
228
+
229
+ ExampleRepresenter.new(example).to_hash
230
+
231
+ #=> {
232
+ #=> name: 'Heidi Shepherd'
233
+ #=> }
234
+ ```
235
+ The lookup order is to first check the object instance and then the representer for a matching method.
236
+
237
+ ###2. Hash key
238
+ ```ruby
239
+ class ExampleRepresenter
240
+ include Supa::Representable
241
+
242
+ define do
243
+ attribute :name, getter: 'full_name'
244
+ end
245
+ end
246
+
247
+ example = {
248
+ 'full_name' => 'Heidi Shepherd'
249
+ }
250
+
251
+ ExampleRepresenter.new(example).to_hash
252
+
253
+ #=> {
254
+ #=> name: 'Heidi Shepherd'
255
+ #=> }
256
+
257
+ ```
191
258
 
192
259
  ### `virtual`
193
260
 
261
+ Virtual is an attribute that doesn't exist in representing object and defind as `string`.
262
+ ```ruby
263
+ class ExampleRepresenter
264
+ include Supa::Representable
265
+
266
+ define do
267
+ attribute :version, getter: 1.0
268
+ attribute :type, getter: 'documentation'
269
+ end
270
+ end
271
+
272
+ ExampleRepresenter.new({}).to_hash
273
+
274
+ {
275
+ version: 1.0,
276
+ type: 'documentation',
277
+ }
278
+ ```
279
+
194
280
  ### `namespace`
195
281
 
196
282
  ### `object`
@@ -223,10 +309,9 @@ bin/console
223
309
 
224
310
  ## Contributing
225
311
 
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
-
312
+ Bug reports and pull requests are welcome on GitHub at https://github.com/distribusion/supa.
313
+ 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.
228
314
 
229
315
  ## License
230
316
 
231
317
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
232
-
data/Rakefile CHANGED
@@ -1,14 +1,6 @@
1
1
  require 'bundler/gem_tasks'
2
- require 'rake/testtask'
2
+ require 'rspec/core/rake_task'
3
3
 
4
- Rake::TestTask.new(:test) do |t|
5
- t.libs << %w(spec lib)
6
- t.test_files = FileList['spec/**/*_spec.rb']
7
- end
4
+ RSpec::Core::RakeTask.new(:spec)
8
5
 
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
6
+ task default: :spec
data/bin/console CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require "bundler/setup"
4
- require "supa"
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 "irb"
14
- IRB.start
13
+ require 'pry-byebug'
14
+ Pry.start
data/lib/supa.rb CHANGED
@@ -1,6 +1,14 @@
1
1
  require 'supa/version'
2
- require 'supa/builder'
3
2
  require 'supa/representable'
3
+ require 'supa/command'
4
+ require 'supa/commands/attribute'
5
+ require 'supa/commands/virtual'
6
+ require 'supa/commands/object'
7
+ require 'supa/commands/namespace'
8
+ require 'supa/commands/collection'
9
+ require 'supa/commands/append'
10
+
11
+ require 'supa/builder'
4
12
 
5
13
  module Supa
6
14
  end
data/lib/supa/builder.rb CHANGED
@@ -1,43 +1,32 @@
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
-
8
1
  module Supa
9
2
  class Builder
10
3
  COMMANDS = %w(attribute virtual object namespace collection append).freeze
11
4
 
5
+ def initialize(subject, representer:, tree:)
6
+ @subject = subject
7
+ @representer = representer
8
+ @tree = tree
9
+ end
10
+
12
11
  COMMANDS.each do |command|
13
12
  klass = Supa::Commands.const_get(command.capitalize)
14
13
 
15
- define_method command do |name, options = {}, &block|
16
- klass.new(representer: representer,
17
- context: context,
18
- tree: tree,
19
- name: name,
20
- options: options,
21
- &block).represent
14
+ define_method(command) do |name, options = {}, &block|
15
+ klass.new(@subject,
16
+ representer: @representer,
17
+ tree: @tree,
18
+ name: name,
19
+ options: options,
20
+ &block).represent
22
21
  end
23
22
  end
24
23
 
25
- def initialize(representer:, context:, tree:)
26
- @representer = representer
27
- @context = context
28
- @tree = tree
29
- end
30
-
31
24
  def to_hash
32
- tree.to_hash
25
+ @tree.to_hash
33
26
  end
34
27
 
35
28
  def to_json
36
29
  to_hash.to_json
37
30
  end
38
-
39
- private
40
-
41
- attr_reader :representer, :context, :tree
42
31
  end
43
32
  end
data/lib/supa/command.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  module Supa
2
2
  class Command
3
- def initialize(representer:, context:, tree:, name:, options: {}, &block)
3
+ def initialize(subject, representer:, tree:, name:, options: {}, &block)
4
+ @subject = subject
4
5
  @representer = representer
5
- @context = context
6
6
  @tree = tree
7
7
  @name = name
8
8
  @options = options
@@ -14,50 +14,47 @@ module Supa
14
14
  end
15
15
 
16
16
  private
17
- attr_reader :representer, :context, :tree, :name, :options, :block
18
17
 
19
- def apply_modifier(value)
20
- with_modifier? ? representer.send(modifier, value) : value
18
+ def value
19
+ return @representer.send(@options[:modifier], apply_render_flags(raw_value)) if @options[:modifier]
20
+ apply_render_flags(raw_value)
21
21
  end
22
22
 
23
- def modifier
24
- options[:modifier]
23
+ def apply_render_flags(val)
24
+ val
25
25
  end
26
26
 
27
- def with_modifier?
28
- !!options[:modifier]
27
+ def raw_value
28
+ exec_on_representer? ? value_from_representer : value_from_subject
29
29
  end
30
30
 
31
- def static_value
32
- value = getter
33
-
34
- apply_modifier(value)
31
+ def value_from_subject
32
+ return @subject[getter] if @subject.is_a?(Hash)
33
+ @subject.send(getter) if @subject
35
34
  end
36
35
 
37
- def dynamic_value
38
- value = if exec_on_object?
39
- value_from_object
40
- else
41
- value_from_representer
42
- end
36
+ def value_from_representer
37
+ @representer.send(getter)
38
+ end
43
39
 
44
- apply_modifier(value)
40
+ def exec_on_representer?
41
+ @options[:exec_context] == :representer
45
42
  end
46
43
 
47
- def exec_on_object?
48
- options[:exec_context] != :representer
44
+ def getter
45
+ @options[:getter] || @name
49
46
  end
50
47
 
51
- def value_from_object
52
- context.is_a?(Hash) ? context[getter] : context.send(getter)
48
+ def hide_when_empty?
49
+ @options.fetch(:hide_when_empty, false)
53
50
  end
54
51
 
55
- def value_from_representer
56
- representer.send(getter)
52
+ def empty_when_nil?
53
+ @options.fetch(:empty_when_nil, false)
57
54
  end
58
55
 
59
- def getter
60
- options[:getter] || @name
56
+ def hide?
57
+ false
61
58
  end
62
59
  end
63
60
  end