onsi 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ed92bde9b8d7540e7d542621101fedc2cb414aaa07d24c751d57d7b4454b0bcb
4
- data.tar.gz: 441c0cd6376b4bcc6c086acb0cbec596fed03f0a190a8096e8dac639be4a28d9
3
+ metadata.gz: 11cdb10f50e5e342639f7957e3e2cf867decc2773065232c3a880983936a5122
4
+ data.tar.gz: f37f95aaddd5d3736a7f165b4362876ef7a7a60865bae5183b7b850ba4ad6746
5
5
  SHA512:
6
- metadata.gz: b1b31fa4f17aad3767d5f4f2b46bf92e52ff6bd9ec7343ab4e742796d41f6791f5944b07378ec3dfd16d11b2b1caca07608fea9ad3dcb911b1a89318d8be15cd
7
- data.tar.gz: 4e0e591bc4fea1df9aeedc73b6f558a12e7a41b42f65a780eff24784bad73c709731af923e1fd97d0346295ff911b66584cd11e74584071f6f0bffbbef176aef
6
+ metadata.gz: fce49cd88116a547bd44bdc835b5def7a2dc5d54b07360d0185bf99008ba66c02a7821dadcc77cf9909bc62549ce57af5d30fd27c1eed9068d67041bdd943638
7
+ data.tar.gz: 452661c725d56fc43dd03a16499321614063830a4cfc6d4af29fb122d6c8349e71f4d122d8d56637fa80eaee80bc89be3a36e55a7aa6b20415db83ffaae6e2e4
data/.circleci/config.yml CHANGED
@@ -16,6 +16,7 @@ jobs:
16
16
  command: |
17
17
  curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
18
18
  chmod +x ./cc-test-reporter
19
+ - run: gem install bundler
19
20
  - restore_cache:
20
21
  keys:
21
22
  - v1-gems-latest-{{ checksum "onsi.gemspec" }}
@@ -44,6 +45,7 @@ jobs:
44
45
  working_directory: ~/repo
45
46
  steps:
46
47
  - checkout
48
+ - run: gem install bundler
47
49
  - restore_cache:
48
50
  keys:
49
51
  - v1-gems-build_2_5-{{ checksum "onsi.gemspec" }}
@@ -65,6 +67,7 @@ jobs:
65
67
  working_directory: ~/repo
66
68
  steps:
67
69
  - checkout
70
+ - run: gem install bundler
68
71
  - restore_cache:
69
72
  keys:
70
73
  - v1-gems-build_2_4-{{ checksum "onsi.gemspec" }}
@@ -86,6 +89,7 @@ jobs:
86
89
  working_directory: ~/repo
87
90
  steps:
88
91
  - checkout
92
+ - run: gem install bundler
89
93
  - restore_cache:
90
94
  keys:
91
95
  - v1-gems-build_2_3-{{ checksum "onsi.gemspec" }}
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- onsi (0.3.0)
4
+ onsi (0.4.0)
5
5
  rails (>= 5.0, < 6.0)
6
6
 
7
7
  GEM
@@ -17,22 +17,11 @@ module Onsi
17
17
 
18
18
  def render_resource(resource, opts = {})
19
19
  version = opts.delete(:version) || self.class.render_version || Model::DEFAULT_API_VERSION
20
- payload = format_resource(resource, version)
20
+ payload = Resource.render(resource, version)
21
21
  render_options = {}
22
- render_options[:json] = { data: payload }
22
+ render_options[:json] = payload
23
23
  render_options.merge!(opts)
24
24
  render(render_options)
25
25
  end
26
-
27
- def format_resource(resource, version)
28
- case resource
29
- when Onsi::Resource
30
- resource
31
- when Enumerable
32
- resource.map { |res| format_resource(res, version) }
33
- else
34
- Onsi::Resource.new(resource, version)
35
- end
36
- end
37
26
  end
38
27
  end
@@ -0,0 +1,56 @@
1
+ module Onsi
2
+ class Includes
3
+ attr_reader :included
4
+
5
+ def initialize(included)
6
+ @included = parse_included(included)
7
+ end
8
+
9
+ def method_missing(name, *args, &block)
10
+ if name =~ /\Afetch_(.*)/
11
+ add_fetch_method(name.to_s.gsub(/\Afetch_/, ''), *args, &block)
12
+ else
13
+ super
14
+ end
15
+ end
16
+
17
+ def load_included
18
+ @load_included ||= {}.tap do |root|
19
+ included.each do |name|
20
+ fetcher = fetch_methods[name]
21
+ next if fetcher.nil?
22
+ results = fetcher.call
23
+ root[name] = results
24
+ end
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def fetch_methods
31
+ @fetch_methods ||= {}
32
+ end
33
+
34
+ def add_fetch_method(name, &block)
35
+ if block.nil?
36
+ raise ArgumentError, "Must specify a block for fetch_#{name}"
37
+ end
38
+ fetch_methods[name.to_sym] = block
39
+ end
40
+
41
+ def parse_included(included)
42
+ case included
43
+ when Enumerable
44
+ included.map(&:to_sym)
45
+ when String
46
+ included.split(',').map(&:to_sym)
47
+ when Symbol
48
+ Array(included)
49
+ when nil
50
+ []
51
+ else
52
+ raise ArgumentError, "Onsi::Includes unknown included type #{included}"
53
+ end
54
+ end
55
+ end
56
+ end
data/lib/onsi/params.rb CHANGED
@@ -72,8 +72,12 @@ module Onsi
72
72
  attributes.to_h.merge(relationships.to_h).with_indifferent_access
73
73
  end
74
74
 
75
+ def fetch(key, default = nil)
76
+ attrs_hash[key] || default
77
+ end
78
+
75
79
  def require(key)
76
- value = attributes.to_h.with_indifferent_access[key]
80
+ value = attrs_hash[key]
77
81
  if value.nil?
78
82
  raise MissingReqiredAttribute.new("Missing attribute #{key}", key)
79
83
  end
@@ -85,5 +89,11 @@ module Onsi
85
89
  rescue ActiveRecord::RecordNotFound
86
90
  raise RelationshipNotFound.new("Can't find relationship #{key}", key)
87
91
  end
92
+
93
+ private
94
+
95
+ def attrs_hash
96
+ @attrs_hash ||= attributes.to_h.with_indifferent_access
97
+ end
88
98
  end
89
99
  end
data/lib/onsi/resource.rb CHANGED
@@ -1,38 +1,107 @@
1
1
  module Onsi
2
2
  class Resource
3
- attr_reader :object, :version
3
+ attr_reader :object, :version, :includes
4
+
5
+ TYPE_KEY = 'type'.freeze
6
+ ID_KEY = 'id'.freeze
7
+ ATTRIBUTES_KEY = 'attributes'.freeze
8
+ RELATIONSHIPS_KEY = 'relationships'.freeze
9
+ META_KEY = 'meta'.freeze
10
+ DATA_KEY = 'data'.freeze
11
+ INCLUDED_KEY = 'included'.freeze
4
12
 
5
13
  class InvalidResourceError < StandardError; end
6
14
 
7
- def initialize(object, version = Model::DEFAULT_API_VERSION)
15
+ class << self
16
+ def as_resource(resource, version)
17
+ case resource
18
+ when Onsi::Resource
19
+ resource
20
+ when Enumerable
21
+ resource.map { |res| as_resource(res, version) }
22
+ else
23
+ Onsi::Resource.new(resource, version)
24
+ end
25
+ end
26
+
27
+ def render(resource, version)
28
+ resources = as_resource(resource, version)
29
+ {}.tap do |root|
30
+ root[DATA_KEY] = resources.as_json
31
+ included = all_included(resources)
32
+ if included.any?
33
+ root[INCLUDED_KEY] = included
34
+ end
35
+ end
36
+ end
37
+
38
+ def all_included(resources)
39
+ Array(resources).map(&:flat_includes).flatten.uniq do |res|
40
+ "#{res[TYPE_KEY]}-#{res[ID_KEY]}"
41
+ end
42
+ end
43
+ end
44
+
45
+ def initialize(object, version = nil, includes: nil)
8
46
  @object = object
9
- @version = version
47
+ @version = version || Model::DEFAULT_API_VERSION
48
+ @includes = includes
10
49
  validate!
11
50
  end
12
51
 
13
52
  def as_json(_opts = {})
14
53
  {}.tap do |root|
15
- root['type'] = type
16
- root['id'] = object.id.to_s
17
- root['attributes'] = generate_attributes
18
- rela = generate_relationships
19
- root['relationships'] = rela if rela.any?
20
- meta = generate_metadata
21
- root['meta'] = meta if meta.any?
54
+ root[TYPE_KEY] = type
55
+ root[ID_KEY] = object.id.to_s
56
+ root[ATTRIBUTES_KEY] = generate_attributes
57
+ append_relationships(root)
58
+ append_meta(root)
59
+ append_includes(root)
22
60
  end
23
61
  end
24
62
 
63
+ def rendered_includes
64
+ @rendered_includes ||= perform_render_includes
65
+ end
66
+
67
+ def flat_includes
68
+ rendered_includes.values.map { |root| root[DATA_KEY] }.flatten
69
+ end
70
+
25
71
  private
26
72
 
27
73
  def validate!
28
- return if object.class.included_modules.include?(Onsi::Model)
29
- raise InvalidResourceError, "Trying to render a #{object.class.name}. But it doesn't include Onsi::Model"
74
+ unless object.class.included_modules.include?(Onsi::Model)
75
+ raise InvalidResourceError, "Trying to render a #{object.class.name}. But it doesn't include Onsi::Model"
76
+ end
77
+ if includes.present? && !includes.is_a?(Onsi::Includes)
78
+ raise InvalidResourceError, "Included resources in #{self} is not a Onsi::Includes"
79
+ end
30
80
  end
31
81
 
32
82
  def type
33
83
  object.class.api_renderer(version, for_render: true).type || object.class.name.underscore
34
84
  end
35
85
 
86
+ def append_relationships(root)
87
+ relationships = generate_relationships
88
+ return unless relationships.any?
89
+ root[RELATIONSHIPS_KEY] = relationships
90
+ end
91
+
92
+ def append_meta(root)
93
+ meta = generate_metadata
94
+ return unless meta.any?
95
+ root[META_KEY] = meta
96
+ end
97
+
98
+ def append_includes(root)
99
+ includes = generate_includes
100
+ return unless includes.any?
101
+ root[RELATIONSHIPS_KEY] ||= {}
102
+ root[RELATIONSHIPS_KEY].merge!(includes)
103
+ end
104
+
36
105
  def generate_attributes
37
106
  object.class.api_renderer(version, for_render: true).render_attributes(object)
38
107
  end
@@ -44,5 +113,40 @@ module Onsi
44
113
  def generate_metadata
45
114
  object.class.api_renderer(version, for_render: true).render_metadata(object)
46
115
  end
116
+
117
+ def generate_includes
118
+ {}.tap do |root|
119
+ rendered_includes.each do |key, values|
120
+ included = values[DATA_KEY]
121
+ case included
122
+ when Array
123
+ root[key] = {}.tap do |subobj|
124
+ subobj[DATA_KEY] = included.map do |inc|
125
+ {
126
+ TYPE_KEY => inc[TYPE_KEY],
127
+ ID_KEY => inc[ID_KEY]
128
+ }
129
+ end
130
+ end
131
+ when Hash
132
+ root[key] = { DATA_KEY => { TYPE_KEY => included[TYPE_KEY], ID_KEY => included[ID_KEY] } }
133
+ end
134
+ end
135
+ end
136
+ end
137
+
138
+ def perform_render_includes
139
+ included = includes&.load_included
140
+ {}.tap do |root|
141
+ Hash(included).each do |key, results|
142
+ root[key.to_s] = {}
143
+ root[key.to_s][DATA_KEY] = render_included(results)
144
+ end
145
+ end
146
+ end
147
+
148
+ def render_included(resources)
149
+ Resource.as_resource(resources, version).as_json
150
+ end
47
151
  end
48
152
  end
data/lib/onsi/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Onsi
2
- VERSION = '0.3.0'.freeze
2
+ VERSION = '0.4.0'.freeze
3
3
  end
data/lib/onsi.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'onsi/controller'
2
2
  require 'onsi/error_responder'
3
3
  require 'onsi/errors'
4
+ require 'onsi/includes'
4
5
  require 'onsi/model'
5
6
  require 'onsi/params'
6
7
  require 'onsi/resource'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: onsi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Skylar Schipper
@@ -166,6 +166,7 @@ files:
166
166
  - lib/onsi/controller.rb
167
167
  - lib/onsi/error_responder.rb
168
168
  - lib/onsi/errors.rb
169
+ - lib/onsi/includes.rb
169
170
  - lib/onsi/model.rb
170
171
  - lib/onsi/params.rb
171
172
  - lib/onsi/resource.rb