grape-entity 0.4.2 → 0.4.3

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/.rubocop.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  AllCops:
2
- Excludes:
2
+ Exclude:
3
3
  - vendor/**
4
4
 
5
5
  LineLength:
@@ -23,15 +23,6 @@ Encoding:
23
23
  # no need to always specify encoding
24
24
  Enabled: false
25
25
 
26
- HashMethods:
27
- # key? instead of has_key?
28
- # value? instead of has_value?
29
- Enabled: false
30
-
31
- StringLiterals:
32
- # use single or double-quoted strings, as you please
33
- Enabled: false
34
-
35
26
  Void:
36
27
  # == operator used in void context in specs
37
28
  Enabled: false
@@ -67,3 +58,6 @@ WordArray:
67
58
  CyclomaticComplexity:
68
59
  Enabled: false
69
60
 
61
+ FileName:
62
+ # allow grape-entity.rb for a require
63
+ Enabled: false
data/.travis.yml CHANGED
@@ -1,7 +1,18 @@
1
1
  language: ruby
2
+
2
3
  cache: bundler
4
+
3
5
  rvm:
6
+ - ruby-head
7
+ - 2.1.1
8
+ - 2.1.0
4
9
  - 2.0.0
5
10
  - 1.9.3
6
11
  - jruby-19mode
7
- - rbx-2.1.1
12
+ - jruby-head
13
+ - rbx-2
14
+
15
+ matrix:
16
+ allow_failures:
17
+ - rvm: ruby-head
18
+ - rvm: jruby-head
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ 0.4.3 (2014-06-12)
2
+ ==================
3
+
4
+ * [#77](https://github.com/intridea/grape-entity/pull/77): Fix compatibility with Rspec 3 - [@justfalter](https://github.com/justfalter).
5
+ * [#76](https://github.com/intridea/grape-entity/pull/76): Improve performance of entity serialization - [@justfalter](https://github.com/justfalter)
6
+
1
7
  0.4.2 (2014-04-03)
2
8
  ==================
3
9
 
data/Gemfile CHANGED
@@ -12,8 +12,7 @@ group :development, :test do
12
12
  gem 'json'
13
13
  gem 'rspec'
14
14
  gem 'rack-test', "~> 0.6.2", :require => "rack/test"
15
- gem 'github-markup'
16
- gem 'rubocop', '~> 0.16.0'
15
+ gem 'rubocop', '0.21.0'
17
16
  end
18
17
 
19
18
  platforms :rbx do
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Grape::Entity
2
2
 
3
- [![Build Status](https://travis-ci.org/agileanimal/grape-entity.png?branch=master)](https://travis-ci.org/agileanimal/grape-entity)
3
+ [![Build Status](https://travis-ci.org/intridea/grape-entity.svg?branch=master)](https://travis-ci.org/intridea/grape-entity)
4
4
 
5
5
  ## Introduction
6
6
 
@@ -86,7 +86,7 @@ expose :ip, if: { type: :full }
86
86
 
87
87
  expose :ip, if: lambda { |instance, options| options[:type] == :full } # exposed if the function evaluates to true
88
88
  expose :ip, if: :type # exposed if :type is available in the options hash
89
- expose :ip, if { type: :full } # exposed if options :type has a value of :full
89
+ expose :ip, if: { type: :full } # exposed if options :type has a value of :full
90
90
 
91
91
  expose :ip, unless: ... # the opposite of :if
92
92
  ```
@@ -110,6 +110,15 @@ expose :contact_info do
110
110
  end
111
111
  ```
112
112
 
113
+ #### Collection Exposure
114
+
115
+ Use `root(plural, singular = nil)` to expose an object or a collection of objects with a root key.
116
+
117
+ ```ruby
118
+ root 'users', 'user'
119
+ expose :id, :name, ...
120
+ ```
121
+
113
122
  #### Runtime Exposure
114
123
 
115
124
  Use a block or a `Proc` to evaluate exposure at runtime. The supplied block or
@@ -172,7 +181,7 @@ expose :text, documentation: { type: "String", desc: "Status update text." }
172
181
 
173
182
  ### Options Hash
174
183
 
175
- The option keys `:version` and `:collection` are always defined. The `:version` key is defined as `api.version`. The `:collection` key is boolean, and defined as `true` if the object presented is an array. The options also contain the runtime environment in `:env`, which includes request parameters in `options[:env][:grape.request.params]`.
184
+ The option keys `:version` and `:collection` are always defined. The `:version` key is defined as `api.version`. The `:collection` key is boolean, and defined as `true` if the object presented is an array. The options also contain the runtime environment in `:env`, which includes request parameters in `options[:env]['grape.request.params']`.
176
185
 
177
186
  Any additional options defined on the entity exposure are included as is. In the following example `user` is set to the value of `current_user`.
178
187
 
@@ -0,0 +1,98 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require 'grape-entity'
3
+ require 'benchmark'
4
+
5
+ module Models
6
+ class School
7
+ attr_reader :classrooms
8
+ def initialize
9
+ @classrooms = []
10
+ end
11
+ end
12
+
13
+ class ClassRoom
14
+ attr_reader :students
15
+ attr_accessor :teacher
16
+ def initialize(opts = {})
17
+ @teacher = opts[:teacher]
18
+ @students = []
19
+ end
20
+ end
21
+
22
+ class Person
23
+ attr_accessor :name
24
+ def initialize(opts = {})
25
+ @name = opts[:name]
26
+ end
27
+ end
28
+
29
+ class Teacher < Models::Person
30
+ attr_accessor :tenure
31
+ def initialize(opts = {})
32
+ super(opts)
33
+ @tenure = opts[:tenure]
34
+ end
35
+ end
36
+
37
+ class Student < Models::Person
38
+ attr_reader :grade
39
+ def initialize(opts = {})
40
+ super(opts)
41
+ @grade = opts[:grade]
42
+ end
43
+ end
44
+ end
45
+
46
+ module Entities
47
+ class School < Grape::Entity
48
+ expose :classrooms, using: 'Entities::ClassRoom'
49
+ end
50
+
51
+ class ClassRoom < Grape::Entity
52
+ expose :teacher, using: 'Entities::Teacher'
53
+ expose :students, using: 'Entities::Student'
54
+ expose :size do |model, _opts|
55
+ model.students.count
56
+ end
57
+ end
58
+
59
+ class Person < Grape::Entity
60
+ expose :name
61
+ end
62
+
63
+ class Student < Entities::Person
64
+ expose :grade
65
+ expose :failing do |model, _opts|
66
+ model.grade == 'F'
67
+ end
68
+ end
69
+
70
+ class Teacher < Entities::Person
71
+ expose :tenure
72
+ end
73
+ end
74
+
75
+ teacher1 = Models::Teacher.new(name: 'John Smith', tenure: 2)
76
+ classroom1 = Models::ClassRoom.new(teacher: teacher1)
77
+ classroom1.students << Models::Student.new(name: 'Bobby', grade: 'A')
78
+ classroom1.students << Models::Student.new(name: 'Billy', grade: 'B')
79
+
80
+ teacher2 = Models::Teacher.new(name: 'Lisa Barns')
81
+ classroom2 = Models::ClassRoom.new(teacher: teacher2, tenure: 15)
82
+ classroom2.students << Models::Student.new(name: 'Eric', grade: 'A')
83
+ classroom2.students << Models::Student.new(name: 'Eddie', grade: 'C')
84
+ classroom2.students << Models::Student.new(name: 'Arnie', grade: 'C')
85
+ classroom2.students << Models::Student.new(name: 'Alvin', grade: 'F')
86
+ school = Models::School.new
87
+ school.classrooms << classroom1
88
+ school.classrooms << classroom2
89
+
90
+ iters = 5000
91
+
92
+ Benchmark.bm do |bm|
93
+ bm.report('serializing') do
94
+ iters.times do
95
+ Entities::School.represent(school, serializable: true)
96
+ end
97
+ end
98
+ end
data/grape-entity.gemspec CHANGED
@@ -1,22 +1,22 @@
1
- $:.push File.expand_path("../lib", __FILE__)
2
- require "grape_entity/version"
1
+ $LOAD_PATH.push File.expand_path('../lib', __FILE__)
2
+ require 'grape_entity/version'
3
3
 
4
4
  Gem::Specification.new do |s|
5
- s.name = "grape-entity"
5
+ s.name = 'grape-entity'
6
6
  s.version = GrapeEntity::VERSION
7
7
  s.platform = Gem::Platform::RUBY
8
- s.authors = ["Michael Bleigh"]
9
- s.email = ["michael@intridea.com"]
10
- s.homepage = "https://github.com/intridea/grape-entity"
11
- s.summary = %q{A simple facade for managing the relationship between your model and API.}
12
- s.description = %q{Extracted from Grape, A Ruby framework for rapid API development with great conventions.}
13
- s.license = "MIT"
8
+ s.authors = ['Michael Bleigh']
9
+ s.email = ['michael@intridea.com']
10
+ s.homepage = 'https://github.com/intridea/grape-entity'
11
+ s.summary = %q(A simple facade for managing the relationship between your model and API.)
12
+ s.description = %q(Extracted from Grape, A Ruby framework for rapid API development with great conventions.)
13
+ s.license = 'MIT'
14
14
 
15
- s.rubyforge_project = "grape-entity"
15
+ s.rubyforge_project = 'grape-entity'
16
16
 
17
17
  s.add_runtime_dependency 'activesupport'
18
18
  s.add_runtime_dependency 'multi_json', '>= 1.3.2'
19
-
19
+
20
20
  s.add_development_dependency 'rake'
21
21
  s.add_development_dependency 'maruku'
22
22
  s.add_development_dependency 'yard'
@@ -25,6 +25,6 @@ Gem::Specification.new do |s|
25
25
 
26
26
  s.files = `git ls-files`.split("\n")
27
27
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
28
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
29
- s.require_paths = ["lib"]
28
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
29
+ s.require_paths = ['lib']
30
30
  end
data/lib/grape_entity.rb CHANGED
@@ -1,3 +1,4 @@
1
- require "active_support/core_ext"
2
- require "grape_entity/version"
3
- require "grape_entity/entity"
1
+ require 'active_support'
2
+ require 'active_support/core_ext'
3
+ require 'grape_entity/version'
4
+ require 'grape_entity/entity'
@@ -127,11 +127,11 @@ module Grape
127
127
  options = merge_options(args.last.is_a?(Hash) ? args.pop : {})
128
128
 
129
129
  if args.size > 1
130
- raise ArgumentError, "You may not use the :as option on multi-attribute exposures." if options[:as]
131
- raise ArgumentError, "You may not use block-setting on multi-attribute exposures." if block_given?
130
+ raise ArgumentError, 'You may not use the :as option on multi-attribute exposures.' if options[:as]
131
+ raise ArgumentError, 'You may not use block-setting on multi-attribute exposures.' if block_given?
132
132
  end
133
133
 
134
- raise ArgumentError, "You may not use block-setting when also using format_with" if block_given? && options[:format_with].respond_to?(:call)
134
+ raise ArgumentError, 'You may not use block-setting when also using format_with' if block_given? && options[:format_with].respond_to?(:call)
135
135
 
136
136
  options[:proc] = block if block_given? && block.parameters.any?
137
137
 
@@ -139,7 +139,9 @@ module Grape
139
139
 
140
140
  args.each do |attribute|
141
141
  unless @nested_attributes.empty?
142
+ orig_attribute = attribute.to_sym
142
143
  attribute = "#{@nested_attributes.last}__#{attribute}"
144
+ nested_attribute_names_hash[attribute.to_sym] = orig_attribute
143
145
  options[:nested] = true
144
146
  nested_exposures_hash[@nested_attributes.last.to_sym] ||= {}
145
147
  nested_exposures_hash[@nested_attributes.last.to_sym][attribute.to_sym] = options
@@ -175,7 +177,9 @@ module Grape
175
177
  # are symbolized references to methods on the containing object, the values are
176
178
  # the options that were passed into expose.
177
179
  def self.exposures
178
- @exposures ||= {}
180
+ return @exposures unless @exposures.nil?
181
+
182
+ @exposures = {}
179
183
 
180
184
  if superclass.respond_to? :exposures
181
185
  @exposures = superclass.exposures.merge(@exposures)
@@ -185,20 +189,39 @@ module Grape
185
189
  end
186
190
 
187
191
  class << self
192
+ attr_accessor :_nested_attribute_names_hash
188
193
  attr_accessor :_nested_exposures_hash
189
194
 
195
+ def nested_attribute_names_hash
196
+ self._nested_attribute_names_hash ||= {}
197
+ end
198
+
190
199
  def nested_exposures_hash
191
200
  self._nested_exposures_hash ||= {}
192
201
  end
193
202
 
203
+ def nested_attribute_names
204
+ return @nested_attribute_names unless @nested_attribute_names.nil?
205
+
206
+ @nested_attribute_names = {}.merge(nested_attribute_names_hash)
207
+
208
+ if superclass.respond_to? :nested_attribute_names
209
+ @nested_attribute_names = superclass.nested_attribute_names.deep_merge(@nested_attribute_names)
210
+ end
211
+
212
+ @nested_attribute_names
213
+ end
214
+
194
215
  def nested_exposures
195
- value = nested_exposures_hash
216
+ return @nested_exposures unless @nested_exposures.nil?
217
+
218
+ @nested_exposures = {}.merge(nested_exposures_hash)
196
219
 
197
220
  if superclass.respond_to? :nested_exposures
198
- value = superclass.nested_exposures.deep_merge(value)
221
+ @nested_exposures = superclass.nested_exposures.deep_merge(@nested_exposures)
199
222
  end
200
223
 
201
- value
224
+ @nested_exposures
202
225
  end
203
226
  end
204
227
 
@@ -247,7 +270,7 @@ module Grape
247
270
  # end
248
271
  #
249
272
  def self.format_with(name, &block)
250
- raise ArgumentError, "You must pass a block for formatters" unless block_given?
273
+ raise ArgumentError, 'You must pass a block for formatters' unless block_given?
251
274
  formatters[name.to_sym] = block
252
275
  end
253
276
 
@@ -328,7 +351,7 @@ module Grape
328
351
  inner = inner.serializable_hash if options[:serializable]
329
352
  end
330
353
 
331
- root_element = if options.has_key?(:root)
354
+ root_element = if options.key?(:root)
332
355
  options[:root]
333
356
  else
334
357
  objects.respond_to?(:to_ary) ? @collection_root : @root
@@ -346,7 +369,7 @@ module Grape
346
369
  end
347
370
 
348
371
  def valid_exposures
349
- exposures.reject { |a, options| options[:nested] }.select do |attribute, exposure_options|
372
+ exposures.reject { |_, options| options[:nested] }.select do |attribute, exposure_options|
350
373
  valid_exposure?(attribute, exposure_options)
351
374
  end
352
375
  end
@@ -404,7 +427,8 @@ module Grape
404
427
  protected
405
428
 
406
429
  def self.name_for(attribute)
407
- attribute.to_s.split('__').last.to_sym
430
+ attribute = attribute.to_sym
431
+ nested_attribute_names[attribute] || attribute
408
432
  end
409
433
 
410
434
  def self.key_for(attribute)
@@ -469,13 +493,16 @@ module Grape
469
493
  def valid_exposure?(attribute, exposure_options)
470
494
  nested_exposures = self.class.nested_exposures_for(attribute)
471
495
  (nested_exposures.any? && nested_exposures.all? { |a, o| valid_exposure?(a, o) }) || \
472
- exposure_options.has_key?(:proc) || \
496
+ exposure_options.key?(:proc) || \
473
497
  !exposure_options[:safe] || \
474
498
  object.respond_to?(self.class.name_for(attribute))
475
499
  end
476
500
 
477
501
  def conditions_met?(exposure_options, options)
478
- if_conditions = (exposure_options[:if_extras] || []).dup
502
+ if_conditions = []
503
+ unless exposure_options[:if_extras].nil?
504
+ if_conditions.concat(exposure_options[:if_extras])
505
+ end
479
506
  if_conditions << exposure_options[:if] unless exposure_options[:if].nil?
480
507
 
481
508
  if_conditions.each do |if_condition|
@@ -486,7 +513,10 @@ module Grape
486
513
  end
487
514
  end
488
515
 
489
- unless_conditions = (exposure_options[:unless_extras] || []).dup
516
+ unless_conditions = []
517
+ unless exposure_options[:unless_extras].nil?
518
+ unless_conditions.concat(exposure_options[:unless_extras])
519
+ end
490
520
  unless_conditions << exposure_options[:unless] unless exposure_options[:unless].nil?
491
521
 
492
522
  unless_conditions.each do |unless_condition|
@@ -500,8 +530,6 @@ module Grape
500
530
  true
501
531
  end
502
532
 
503
- private
504
-
505
533
  # All supported options.
506
534
  OPTIONS = [
507
535
  :as, :if, :unless, :using, :with, :proc, :documentation, :format_with, :safe, :if_extras, :unless_extras
@@ -544,7 +572,7 @@ module Grape
544
572
  raise ArgumentError, "#{key.inspect} is not a valid option." unless OPTIONS.include?(key)
545
573
  end
546
574
 
547
- options[:using] = options.delete(:with) if options.has_key?(:with)
575
+ options[:using] = options.delete(:with) if options.key?(:with)
548
576
  options
549
577
  end
550
578
  end
@@ -1,3 +1,3 @@
1
1
  module GrapeEntity
2
- VERSION = '0.4.2'
2
+ VERSION = '0.4.3'
3
3
  end
@@ -46,7 +46,7 @@ describe Grape::Entity do
46
46
  attr_accessor :prop1
47
47
 
48
48
  def initialize
49
- @prop1 = "value1"
49
+ @prop1 = 'value1'
50
50
  end
51
51
  end
52
52
 
@@ -56,7 +56,7 @@ describe Grape::Entity do
56
56
  end
57
57
 
58
58
  subject.expose(:bogus, using: EntitySpec::BogusEntity) do |entity|
59
- entity.prop1 = "MODIFIED 2"
59
+ entity.prop1 = 'MODIFIED 2'
60
60
  entity
61
61
  end
62
62
 
@@ -65,7 +65,7 @@ describe Grape::Entity do
65
65
  value.should be_instance_of EntitySpec::BogusEntity
66
66
 
67
67
  prop1 = value.send(:value_for, :prop1)
68
- prop1.should == "MODIFIED 2"
68
+ prop1.should == 'MODIFIED 2'
69
69
  end
70
70
 
71
71
  context 'with parameters passed to the block' do
@@ -100,37 +100,37 @@ describe Grape::Entity do
100
100
 
101
101
  it 'represents the exposure as a hash of its nested exposures' do
102
102
  subject.expose :awesome do
103
- subject.expose(:nested) { |_| "value" }
104
- subject.expose(:another_nested) { |_| "value" }
103
+ subject.expose(:nested) { |_| 'value' }
104
+ subject.expose(:another_nested) { |_| 'value' }
105
105
  end
106
106
 
107
107
  subject.represent({}).send(:value_for, :awesome).should == {
108
- nested: "value",
109
- another_nested: "value"
108
+ nested: 'value',
109
+ another_nested: 'value'
110
110
  }
111
111
  end
112
112
 
113
113
  it 'does not represent attributes, declared inside nested exposure, outside of it' do
114
114
  subject.expose :awesome do
115
- subject.expose(:nested) { |_| "value" }
116
- subject.expose(:another_nested) { |_| "value" }
115
+ subject.expose(:nested) { |_| 'value' }
116
+ subject.expose(:another_nested) { |_| 'value' }
117
117
  subject.expose :second_level_nested do
118
- subject.expose(:deeply_exposed_attr) { |_| "value" }
118
+ subject.expose(:deeply_exposed_attr) { |_| 'value' }
119
119
  end
120
120
  end
121
121
 
122
122
  subject.represent({}).serializable_hash.should == {
123
123
  awesome: {
124
- nested: "value",
125
- another_nested: "value",
124
+ nested: 'value',
125
+ another_nested: 'value',
126
126
  second_level_nested: {
127
- deeply_exposed_attr: "value"
127
+ deeply_exposed_attr: 'value'
128
128
  }
129
129
  }
130
130
  }
131
131
  end
132
132
 
133
- it "complex nested attributes" do
133
+ it 'complex nested attributes' do
134
134
  class ClassRoom < Grape::Entity
135
135
  expose(:parents, using: 'Parent') { |_| [{}, {}] }
136
136
  end
@@ -157,15 +157,15 @@ describe Grape::Entity do
157
157
  {
158
158
  user: { in_first: 'value' },
159
159
  children: [
160
- { user: { in_first: 'value', user_id: "value", display_id: "value" } },
161
- { user: { in_first: 'value', user_id: "value", display_id: "value" } }
160
+ { user: { in_first: 'value', user_id: 'value', display_id: 'value' } },
161
+ { user: { in_first: 'value', user_id: 'value', display_id: 'value' } }
162
162
  ]
163
163
  },
164
164
  {
165
165
  user: { in_first: 'value' },
166
166
  children: [
167
- { user: { in_first: 'value', user_id: "value", display_id: "value" } },
168
- { user: { in_first: 'value', user_id: "value", display_id: "value" } }
167
+ { user: { in_first: 'value', user_id: 'value', display_id: 'value' } },
168
+ { user: { in_first: 'value', user_id: 'value', display_id: 'value' } }
169
169
  ]
170
170
  }
171
171
  ]
@@ -175,7 +175,7 @@ describe Grape::Entity do
175
175
  it 'is safe if its nested exposures are safe' do
176
176
  subject.with_options safe: true do
177
177
  subject.expose :awesome do
178
- subject.expose(:nested) { |_| "value" }
178
+ subject.expose(:nested) { |_| 'value' }
179
179
  end
180
180
  subject.expose :not_awesome do
181
181
  subject.expose :nested
@@ -252,12 +252,12 @@ describe Grape::Entity do
252
252
  it 'formats an exposure with a :format_with lambda that returns a value from the entity instance' do
253
253
  object = Hash.new
254
254
 
255
- subject.expose(:size, format_with: lambda { |value| self.object.class.to_s })
255
+ subject.expose(:size, format_with: lambda { |_value| self.object.class.to_s })
256
256
  subject.represent(object).send(:value_for, :size).should == object.class.to_s
257
257
  end
258
258
 
259
259
  it 'formats an exposure with a :format_with symbol that returns a value from the entity instance' do
260
- subject.format_with :size_formatter do |date|
260
+ subject.format_with :size_formatter do |_date|
261
261
  self.object.class.to_s
262
262
  end
263
263
 
@@ -312,8 +312,8 @@ describe Grape::Entity do
312
312
  subject.exposures[:awesome_thing].should == { as: :extra_smooth }
313
313
  end
314
314
 
315
- it "merges nested :if option" do
316
- match_proc = lambda { |obj, opts| true }
315
+ it 'merges nested :if option' do
316
+ match_proc = lambda { |_obj, _opts| true }
317
317
 
318
318
  subject.class_eval do
319
319
  # Symbol
@@ -338,7 +338,7 @@ describe Grape::Entity do
338
338
  end
339
339
 
340
340
  it 'merges nested :unless option' do
341
- match_proc = lambda { |obj, opts| true }
341
+ match_proc = lambda { |_, _| true }
342
342
 
343
343
  subject.class_eval do
344
344
  # Symbol
@@ -382,10 +382,10 @@ describe Grape::Entity do
382
382
  end
383
383
 
384
384
  it 'overrides nested :proc option' do
385
- match_proc = lambda { |obj, opts| 'more awesomer' }
385
+ match_proc = lambda { |_obj, _opts| 'more awesomer' }
386
386
 
387
387
  subject.class_eval do
388
- with_options(proc: lambda { |obj, opts| 'awesome' }) do
388
+ with_options(proc: lambda { |_obj, _opts| 'awesome' }) do
389
389
  expose :awesome_thing, proc: match_proc
390
390
  end
391
391
  end
@@ -422,7 +422,7 @@ describe Grape::Entity do
422
422
 
423
423
  it 'adds the collection: true option if called with a collection' do
424
424
  representation = subject.represent(4.times.map { Object.new })
425
- representation.each { |r| r.options[:collection].should be_true }
425
+ representation.each { |r| r.options[:collection].should be true }
426
426
  end
427
427
 
428
428
  it 'returns a serialized hash of a single object if serializable: true' do
@@ -557,8 +557,8 @@ describe Grape::Entity do
557
557
  birthday: Time.gm(2012, 2, 27),
558
558
  fantasies: ['Unicorns', 'Double Rainbows', 'Nessy'],
559
559
  friends: [
560
- double(name: "Friend 1", email: 'friend1@example.com', fantasies: [], birthday: Time.gm(2012, 2, 27), friends: []),
561
- double(name: "Friend 2", email: 'friend2@example.com', fantasies: [], birthday: Time.gm(2012, 2, 27), friends: [])
560
+ double(name: 'Friend 1', email: 'friend1@example.com', fantasies: [], birthday: Time.gm(2012, 2, 27), friends: []),
561
+ double(name: 'Friend 2', email: 'friend2@example.com', fantasies: [], birthday: Time.gm(2012, 2, 27), friends: [])
562
562
  ]
563
563
  }
564
564
  }
@@ -575,7 +575,7 @@ describe Grape::Entity do
575
575
  expect { fresh_class.new(nil).serializable_hash }.not_to raise_error
576
576
  end
577
577
 
578
- context "with safe option" do
578
+ context 'with safe option' do
579
579
  it 'does not throw an exception when an attribute is not found on the object' do
580
580
  fresh_class.expose :name, :nonexistent_attribute, safe: true
581
581
  expect { fresh_class.new(model).serializable_hash }.not_to raise_error
@@ -602,24 +602,24 @@ describe Grape::Entity do
602
602
  end
603
603
  end
604
604
 
605
- context "without safe option" do
605
+ context 'without safe option' do
606
606
  it 'throws an exception when an attribute is not found on the object' do
607
607
  fresh_class.expose :name, :nonexistent_attribute
608
608
  expect { fresh_class.new(model).serializable_hash }.to raise_error
609
609
  end
610
610
 
611
611
  it "exposes attributes that don't exist on the object only when they are generated by a block" do
612
- fresh_class.expose :nonexistent_attribute do |model, _|
613
- "well, I do exist after all"
612
+ fresh_class.expose :nonexistent_attribute do |_model, _opts|
613
+ 'well, I do exist after all'
614
614
  end
615
615
  res = fresh_class.new(model).serializable_hash
616
616
  res.should have_key :nonexistent_attribute
617
617
  end
618
618
 
619
- it "does not expose attributes that are generated by a block but have not passed criteria" do
620
- fresh_class.expose :nonexistent_attribute, proc: lambda { |model, _|
621
- "I exist, but it is not yet my time to shine"
622
- }, if: lambda { |model, _| false }
619
+ it 'does not expose attributes that are generated by a block but have not passed criteria' do
620
+ fresh_class.expose :nonexistent_attribute, proc: lambda { |_model, _opts|
621
+ 'I exist, but it is not yet my time to shine'
622
+ }, if: lambda { |_model, _opts| false }
623
623
  res = fresh_class.new(model).serializable_hash
624
624
  res.should_not have_key :nonexistent_attribute
625
625
  end
@@ -631,17 +631,17 @@ describe Grape::Entity do
631
631
  end
632
632
  end
633
633
 
634
- fresh_class.expose :nonexistent_attribute, using: EntitySpec::TestEntity do |model, _|
635
- "well, I do exist after all"
634
+ fresh_class.expose :nonexistent_attribute, using: EntitySpec::TestEntity do |_model, _opts|
635
+ 'well, I do exist after all'
636
636
  end
637
637
  res = fresh_class.new(model).serializable_hash
638
638
  res.should have_key :nonexistent_attribute
639
639
  end
640
640
 
641
- it "does not expose attributes that are generated by a block but have not passed criteria" do
642
- fresh_class.expose :nonexistent_attribute, proc: lambda { |model, _|
643
- "I exist, but it is not yet my time to shine"
644
- }, if: lambda { |model, _| false }
641
+ it 'does not expose attributes that are generated by a block but have not passed criteria' do
642
+ fresh_class.expose :nonexistent_attribute, proc: lambda { |_, _|
643
+ 'I exist, but it is not yet my time to shine'
644
+ }, if: lambda { |_, _| false }
645
645
  res = fresh_class.new(model).serializable_hash
646
646
  res.should_not have_key :nonexistent_attribute
647
647
  end
@@ -649,14 +649,14 @@ describe Grape::Entity do
649
649
  context '#serializable_hash' do
650
650
  module EntitySpec
651
651
  class EmbeddedExample
652
- def serializable_hash(opts = {})
652
+ def serializable_hash(_opts = {})
653
653
  { abc: 'def' }
654
654
  end
655
655
  end
656
656
 
657
657
  class EmbeddedExampleWithHash
658
658
  def name
659
- "abc"
659
+ 'abc'
660
660
  end
661
661
 
662
662
  def embedded
@@ -666,7 +666,7 @@ describe Grape::Entity do
666
666
 
667
667
  class EmbeddedExampleWithMany
668
668
  def name
669
- "abc"
669
+ 'abc'
670
670
  end
671
671
 
672
672
  def embedded
@@ -676,7 +676,7 @@ describe Grape::Entity do
676
676
 
677
677
  class EmbeddedExampleWithOne
678
678
  def name
679
- "abc"
679
+ 'abc'
680
680
  end
681
681
 
682
682
  def embedded
@@ -688,19 +688,19 @@ describe Grape::Entity do
688
688
  it 'serializes embedded objects which respond to #serializable_hash' do
689
689
  fresh_class.expose :name, :embedded
690
690
  presenter = fresh_class.new(EntitySpec::EmbeddedExampleWithOne.new)
691
- presenter.serializable_hash.should == { name: "abc", embedded: { abc: "def" } }
691
+ presenter.serializable_hash.should == { name: 'abc', embedded: { abc: 'def' } }
692
692
  end
693
693
 
694
694
  it 'serializes embedded arrays of objects which respond to #serializable_hash' do
695
695
  fresh_class.expose :name, :embedded
696
696
  presenter = fresh_class.new(EntitySpec::EmbeddedExampleWithMany.new)
697
- presenter.serializable_hash.should == { name: "abc", embedded: [{ abc: "def" }, { abc: "def" }] }
697
+ presenter.serializable_hash.should == { name: 'abc', embedded: [{ abc: 'def' }, { abc: 'def' }] }
698
698
  end
699
699
 
700
700
  it 'serializes embedded hashes of objects which respond to #serializable_hash' do
701
701
  fresh_class.expose :name, :embedded
702
702
  presenter = fresh_class.new(EntitySpec::EmbeddedExampleWithHash.new)
703
- presenter.serializable_hash.should == { name: "abc", embedded: { a: nil, b: { abc: "def" } } }
703
+ presenter.serializable_hash.should == { name: 'abc', embedded: { a: nil, b: { abc: 'def' } } }
704
704
  end
705
705
  end
706
706
  end
@@ -755,7 +755,7 @@ describe Grape::Entity do
755
755
  rep.last.serializable_hash[:name].should == 'Friend 2'
756
756
  end
757
757
 
758
- it "passes through the proc which returns an array of objects with custom options(:using)" do
758
+ it 'passes through the proc which returns an array of objects with custom options(:using)' do
759
759
  module EntitySpec
760
760
  class FriendEntity < Grape::Entity
761
761
  root 'friends', 'friend'
@@ -764,7 +764,7 @@ describe Grape::Entity do
764
764
  end
765
765
 
766
766
  fresh_class.class_eval do
767
- expose :custom_friends, using: EntitySpec::FriendEntity do |user, options|
767
+ expose :custom_friends, using: EntitySpec::FriendEntity do |user, _opts|
768
768
  user.friends
769
769
  end
770
770
  end
@@ -776,7 +776,7 @@ describe Grape::Entity do
776
776
  rep.last.serializable_hash.should == { name: 'Friend 2', email: 'friend2@example.com' }
777
777
  end
778
778
 
779
- it "passes through the proc which returns single object with custom options(:using)" do
779
+ it 'passes through the proc which returns single object with custom options(:using)' do
780
780
  module EntitySpec
781
781
  class FriendEntity < Grape::Entity
782
782
  root 'friends', 'friend'
@@ -785,7 +785,7 @@ describe Grape::Entity do
785
785
  end
786
786
 
787
787
  fresh_class.class_eval do
788
- expose :first_friend, using: EntitySpec::FriendEntity do |user, options|
788
+ expose :first_friend, using: EntitySpec::FriendEntity do |user, _opts|
789
789
  user.friends.first
790
790
  end
791
791
  end
@@ -795,7 +795,7 @@ describe Grape::Entity do
795
795
  rep.serializable_hash.should == { name: 'Friend 1', email: 'friend1@example.com' }
796
796
  end
797
797
 
798
- it "passes through the proc which returns empty with custom options(:using)" do
798
+ it 'passes through the proc which returns empty with custom options(:using)' do
799
799
  module EntitySpec
800
800
  class FriendEntity < Grape::Entity
801
801
  root 'friends', 'friend'
@@ -804,8 +804,7 @@ describe Grape::Entity do
804
804
  end
805
805
 
806
806
  fresh_class.class_eval do
807
- expose :first_friend, using: EntitySpec::FriendEntity do |user, options|
808
-
807
+ expose :first_friend, using: EntitySpec::FriendEntity do |_user, _opts|
809
808
  end
810
809
  end
811
810
 
@@ -873,7 +872,7 @@ describe Grape::Entity do
873
872
  subject.send(:value_for, :fantasies).should == ['Nessy', 'Double Rainbows', 'Unicorns']
874
873
  end
875
874
 
876
- it "tries instance methods on the entity first" do
875
+ it 'tries instance methods on the entity first' do
877
876
  module EntitySpec
878
877
  class DelegatingEntity < Grape::Entity
879
878
  root 'friends', 'friend'
@@ -883,18 +882,18 @@ describe Grape::Entity do
883
882
  private
884
883
 
885
884
  def name
886
- "cooler name"
885
+ 'cooler name'
887
886
  end
888
887
  end
889
888
  end
890
889
 
891
- friend = double("Friend", name: "joe", email: "joe@example.com")
890
+ friend = double('Friend', name: 'joe', email: 'joe@example.com')
892
891
  rep = EntitySpec::DelegatingEntity.new(friend)
893
- rep.send(:value_for, :name).should == "cooler name"
894
- rep.send(:value_for, :email).should == "joe@example.com"
892
+ rep.send(:value_for, :name).should == 'cooler name'
893
+ rep.send(:value_for, :email).should == 'joe@example.com'
895
894
  end
896
895
 
897
- context "using" do
896
+ context 'using' do
898
897
  before do
899
898
  module EntitySpec
900
899
  class UserEntity < Grape::Entity
@@ -902,15 +901,15 @@ describe Grape::Entity do
902
901
  end
903
902
  end
904
903
  end
905
- it "string" do
904
+ it 'string' do
906
905
  fresh_class.class_eval do
907
- expose :friends, using: "EntitySpec::UserEntity"
906
+ expose :friends, using: 'EntitySpec::UserEntity'
908
907
  end
909
908
 
910
909
  rep = subject.send(:value_for, :friends)
911
910
  rep.should be_kind_of Array
912
911
  rep.size.should == 2
913
- rep.all? { |r| r.is_a?(EntitySpec::UserEntity) }.should be_true
912
+ rep.all? { |r| r.is_a?(EntitySpec::UserEntity) }.should be true
914
913
  end
915
914
 
916
915
  it 'class' do
@@ -921,7 +920,7 @@ describe Grape::Entity do
921
920
  rep = subject.send(:value_for, :friends)
922
921
  rep.should be_kind_of Array
923
922
  rep.size.should == 2
924
- rep.all? { |r| r.is_a?(EntitySpec::UserEntity) }.should be_true
923
+ rep.all? { |r| r.is_a?(EntitySpec::UserEntity) }.should be true
925
924
  end
926
925
  end
927
926
  end
@@ -934,7 +933,7 @@ describe Grape::Entity do
934
933
  end
935
934
 
936
935
  it 'returns each defined documentation hash' do
937
- doc = { type: "foo", desc: "bar" }
936
+ doc = { type: 'foo', desc: 'bar' }
938
937
  fresh_class.expose :name, documentation: doc
939
938
  fresh_class.expose :email, documentation: doc
940
939
  fresh_class.expose :birthday
@@ -943,7 +942,7 @@ describe Grape::Entity do
943
942
  end
944
943
 
945
944
  it 'returns each defined documentation hash with :as param considering' do
946
- doc = { type: "foo", desc: "bar" }
945
+ doc = { type: 'foo', desc: 'bar' }
947
946
  fresh_class.expose :name, documentation: doc, as: :label
948
947
  fresh_class.expose :email, documentation: doc
949
948
  fresh_class.expose :birthday
@@ -973,54 +972,54 @@ describe Grape::Entity do
973
972
  it 'only passes through hash :if exposure if all attributes match' do
974
973
  exposure_options = { if: { condition1: true, condition2: true } }
975
974
 
976
- subject.send(:conditions_met?, exposure_options, {}).should be_false
977
- subject.send(:conditions_met?, exposure_options, condition1: true).should be_false
978
- subject.send(:conditions_met?, exposure_options, condition1: true, condition2: true).should be_true
979
- subject.send(:conditions_met?, exposure_options, condition1: false, condition2: true).should be_false
980
- subject.send(:conditions_met?, exposure_options, condition1: true, condition2: true, other: true).should be_true
975
+ subject.send(:conditions_met?, exposure_options, {}).should be false
976
+ subject.send(:conditions_met?, exposure_options, condition1: true).should be false
977
+ subject.send(:conditions_met?, exposure_options, condition1: true, condition2: true).should be true
978
+ subject.send(:conditions_met?, exposure_options, condition1: false, condition2: true).should be false
979
+ subject.send(:conditions_met?, exposure_options, condition1: true, condition2: true, other: true).should be true
981
980
  end
982
981
 
983
982
  it 'looks for presence/truthiness if a symbol is passed' do
984
983
  exposure_options = { if: :condition1 }
985
984
 
986
- subject.send(:conditions_met?, exposure_options, {}).should be_false
987
- subject.send(:conditions_met?, exposure_options, condition1: true).should be_true
988
- subject.send(:conditions_met?, exposure_options, condition1: false).should be_false
989
- subject.send(:conditions_met?, exposure_options, condition1: nil).should be_false
985
+ subject.send(:conditions_met?, exposure_options, {}).should be false
986
+ subject.send(:conditions_met?, exposure_options, condition1: true).should be true
987
+ subject.send(:conditions_met?, exposure_options, condition1: false).should be false
988
+ subject.send(:conditions_met?, exposure_options, condition1: nil).should be false
990
989
  end
991
990
 
992
991
  it 'looks for absence/falsiness if a symbol is passed' do
993
992
  exposure_options = { unless: :condition1 }
994
993
 
995
- subject.send(:conditions_met?, exposure_options, {}).should be_true
996
- subject.send(:conditions_met?, exposure_options, condition1: true).should be_false
997
- subject.send(:conditions_met?, exposure_options, condition1: false).should be_true
998
- subject.send(:conditions_met?, exposure_options, condition1: nil).should be_true
994
+ subject.send(:conditions_met?, exposure_options, {}).should be true
995
+ subject.send(:conditions_met?, exposure_options, condition1: true).should be false
996
+ subject.send(:conditions_met?, exposure_options, condition1: false).should be true
997
+ subject.send(:conditions_met?, exposure_options, condition1: nil).should be true
999
998
  end
1000
999
 
1001
1000
  it 'only passes through proc :if exposure if it returns truthy value' do
1002
1001
  exposure_options = { if: lambda { |_, opts| opts[:true] } }
1003
1002
 
1004
- subject.send(:conditions_met?, exposure_options, true: false).should be_false
1005
- subject.send(:conditions_met?, exposure_options, true: true).should be_true
1003
+ subject.send(:conditions_met?, exposure_options, true: false).should be false
1004
+ subject.send(:conditions_met?, exposure_options, true: true).should be true
1006
1005
  end
1007
1006
 
1008
1007
  it 'only passes through hash :unless exposure if any attributes do not match' do
1009
1008
  exposure_options = { unless: { condition1: true, condition2: true } }
1010
1009
 
1011
- subject.send(:conditions_met?, exposure_options, {}).should be_true
1012
- subject.send(:conditions_met?, exposure_options, condition1: true).should be_false
1013
- subject.send(:conditions_met?, exposure_options, condition1: true, condition2: true).should be_false
1014
- subject.send(:conditions_met?, exposure_options, condition1: false, condition2: true).should be_false
1015
- subject.send(:conditions_met?, exposure_options, condition1: true, condition2: true, other: true).should be_false
1016
- subject.send(:conditions_met?, exposure_options, condition1: false, condition2: false).should be_true
1010
+ subject.send(:conditions_met?, exposure_options, {}).should be true
1011
+ subject.send(:conditions_met?, exposure_options, condition1: true).should be false
1012
+ subject.send(:conditions_met?, exposure_options, condition1: true, condition2: true).should be false
1013
+ subject.send(:conditions_met?, exposure_options, condition1: false, condition2: true).should be false
1014
+ subject.send(:conditions_met?, exposure_options, condition1: true, condition2: true, other: true).should be false
1015
+ subject.send(:conditions_met?, exposure_options, condition1: false, condition2: false).should be true
1017
1016
  end
1018
1017
 
1019
1018
  it 'only passes through proc :unless exposure if it returns falsy value' do
1020
1019
  exposure_options = { unless: lambda { |_, options| options[:true] == true } }
1021
1020
 
1022
- subject.send(:conditions_met?, exposure_options, true: false).should be_true
1023
- subject.send(:conditions_met?, exposure_options, true: true).should be_false
1021
+ subject.send(:conditions_met?, exposure_options, true: false).should be true
1022
+ subject.send(:conditions_met?, exposure_options, true: true).should be false
1024
1023
  end
1025
1024
  end
1026
1025
 
metadata CHANGED
@@ -1,88 +1,100 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grape-entity
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.4.3
5
+ prerelease:
5
6
  platform: ruby
6
7
  authors:
7
8
  - Michael Bleigh
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2014-04-03 00:00:00.000000000 Z
12
+ date: 2014-06-12 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: activesupport
15
16
  requirement: !ruby/object:Gem::Requirement
17
+ none: false
16
18
  requirements:
17
- - - '>='
19
+ - - ! '>='
18
20
  - !ruby/object:Gem::Version
19
21
  version: '0'
20
22
  type: :runtime
21
23
  prerelease: false
22
24
  version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
23
26
  requirements:
24
- - - '>='
27
+ - - ! '>='
25
28
  - !ruby/object:Gem::Version
26
29
  version: '0'
27
30
  - !ruby/object:Gem::Dependency
28
31
  name: multi_json
29
32
  requirement: !ruby/object:Gem::Requirement
33
+ none: false
30
34
  requirements:
31
- - - '>='
35
+ - - ! '>='
32
36
  - !ruby/object:Gem::Version
33
37
  version: 1.3.2
34
38
  type: :runtime
35
39
  prerelease: false
36
40
  version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
37
42
  requirements:
38
- - - '>='
43
+ - - ! '>='
39
44
  - !ruby/object:Gem::Version
40
45
  version: 1.3.2
41
46
  - !ruby/object:Gem::Dependency
42
47
  name: rake
43
48
  requirement: !ruby/object:Gem::Requirement
49
+ none: false
44
50
  requirements:
45
- - - '>='
51
+ - - ! '>='
46
52
  - !ruby/object:Gem::Version
47
53
  version: '0'
48
54
  type: :development
49
55
  prerelease: false
50
56
  version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
51
58
  requirements:
52
- - - '>='
59
+ - - ! '>='
53
60
  - !ruby/object:Gem::Version
54
61
  version: '0'
55
62
  - !ruby/object:Gem::Dependency
56
63
  name: maruku
57
64
  requirement: !ruby/object:Gem::Requirement
65
+ none: false
58
66
  requirements:
59
- - - '>='
67
+ - - ! '>='
60
68
  - !ruby/object:Gem::Version
61
69
  version: '0'
62
70
  type: :development
63
71
  prerelease: false
64
72
  version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
65
74
  requirements:
66
- - - '>='
75
+ - - ! '>='
67
76
  - !ruby/object:Gem::Version
68
77
  version: '0'
69
78
  - !ruby/object:Gem::Dependency
70
79
  name: yard
71
80
  requirement: !ruby/object:Gem::Requirement
81
+ none: false
72
82
  requirements:
73
- - - '>='
83
+ - - ! '>='
74
84
  - !ruby/object:Gem::Version
75
85
  version: '0'
76
86
  type: :development
77
87
  prerelease: false
78
88
  version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
79
90
  requirements:
80
- - - '>='
91
+ - - ! '>='
81
92
  - !ruby/object:Gem::Version
82
93
  version: '0'
83
94
  - !ruby/object:Gem::Dependency
84
95
  name: rspec
85
96
  requirement: !ruby/object:Gem::Requirement
97
+ none: false
86
98
  requirements:
87
99
  - - ~>
88
100
  - !ruby/object:Gem::Version
@@ -90,6 +102,7 @@ dependencies:
90
102
  type: :development
91
103
  prerelease: false
92
104
  version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
93
106
  requirements:
94
107
  - - ~>
95
108
  - !ruby/object:Gem::Version
@@ -97,15 +110,17 @@ dependencies:
97
110
  - !ruby/object:Gem::Dependency
98
111
  name: bundler
99
112
  requirement: !ruby/object:Gem::Requirement
113
+ none: false
100
114
  requirements:
101
- - - '>='
115
+ - - ! '>='
102
116
  - !ruby/object:Gem::Version
103
117
  version: '0'
104
118
  type: :development
105
119
  prerelease: false
106
120
  version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
107
122
  requirements:
108
- - - '>='
123
+ - - ! '>='
109
124
  - !ruby/object:Gem::Version
110
125
  version: '0'
111
126
  description: Extracted from Grape, A Ruby framework for rapid API development with
@@ -129,6 +144,7 @@ files:
129
144
  - README.md
130
145
  - RELEASING.md
131
146
  - Rakefile
147
+ - bench/serializing.rb
132
148
  - grape-entity.gemspec
133
149
  - lib/grape-entity.rb
134
150
  - lib/grape_entity.rb
@@ -139,26 +155,33 @@ files:
139
155
  homepage: https://github.com/intridea/grape-entity
140
156
  licenses:
141
157
  - MIT
142
- metadata: {}
143
158
  post_install_message:
144
159
  rdoc_options: []
145
160
  require_paths:
146
161
  - lib
147
162
  required_ruby_version: !ruby/object:Gem::Requirement
163
+ none: false
148
164
  requirements:
149
- - - '>='
165
+ - - ! '>='
150
166
  - !ruby/object:Gem::Version
151
167
  version: '0'
168
+ segments:
169
+ - 0
170
+ hash: -128903481528041369
152
171
  required_rubygems_version: !ruby/object:Gem::Requirement
172
+ none: false
153
173
  requirements:
154
- - - '>='
174
+ - - ! '>='
155
175
  - !ruby/object:Gem::Version
156
176
  version: '0'
177
+ segments:
178
+ - 0
179
+ hash: -128903481528041369
157
180
  requirements: []
158
181
  rubyforge_project: grape-entity
159
- rubygems_version: 2.0.14
182
+ rubygems_version: 1.8.25
160
183
  signing_key:
161
- specification_version: 4
184
+ specification_version: 3
162
185
  summary: A simple facade for managing the relationship between your model and API.
163
186
  test_files:
164
187
  - spec/grape_entity/entity_spec.rb
checksums.yaml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- SHA1:
3
- metadata.gz: 4165ed088e82e10584f53bf9436053d18c647b41
4
- data.tar.gz: be2d0321743d7d27dcc1d3c1f30a9e5483e5c92d
5
- SHA512:
6
- metadata.gz: 2059bf88e77709d197f923e0c4659747d83ed2a859325cecdcbb286cdc828a82a07a8c6571df886be941059b6c2c98110327c04809d453824ff377d387919c5e
7
- data.tar.gz: e2c16d535392af2daf37b834589f63933f66f960c15e199956419dd894a3bd95ab06b76a53b3ca594714f854845c4137b65add706b8be02c8d6e580b7d3e2062