active_model_serializers 0.10.0 → 0.10.1

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.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +31 -2
  3. data/Gemfile +1 -1
  4. data/README.md +21 -24
  5. data/active_model_serializers.gemspec +4 -8
  6. data/docs/general/adapters.md +4 -2
  7. data/docs/general/configuration_options.md +6 -1
  8. data/docs/general/deserialization.md +1 -1
  9. data/docs/general/serializers.md +30 -3
  10. data/docs/jsonapi/schema.md +1 -1
  11. data/lib/active_model/serializer.rb +54 -11
  12. data/lib/active_model/serializer/adapter/base.rb +2 -0
  13. data/lib/active_model/serializer/associations.rb +4 -5
  14. data/lib/active_model/serializer/belongs_to_reflection.rb +0 -3
  15. data/lib/active_model/serializer/caching.rb +62 -110
  16. data/lib/active_model/serializer/collection_serializer.rb +30 -10
  17. data/lib/active_model/serializer/configuration.rb +1 -0
  18. data/lib/active_model/serializer/has_many_reflection.rb +0 -3
  19. data/lib/active_model/serializer/has_one_reflection.rb +0 -3
  20. data/lib/active_model/serializer/reflection.rb +3 -3
  21. data/lib/active_model/serializer/version.rb +1 -1
  22. data/lib/active_model_serializers.rb +6 -0
  23. data/lib/active_model_serializers/adapter.rb +6 -0
  24. data/lib/active_model_serializers/adapter/attributes.rb +2 -67
  25. data/lib/active_model_serializers/adapter/base.rb +38 -38
  26. data/lib/active_model_serializers/adapter/json_api.rb +36 -28
  27. data/lib/active_model_serializers/adapter/json_api/link.rb +1 -1
  28. data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +8 -1
  29. data/lib/active_model_serializers/deprecate.rb +1 -2
  30. data/lib/active_model_serializers/deserialization.rb +2 -0
  31. data/lib/active_model_serializers/model.rb +2 -0
  32. data/lib/active_model_serializers/railtie.rb +2 -0
  33. data/lib/active_model_serializers/register_jsonapi_renderer.rb +34 -23
  34. data/lib/active_model_serializers/serialization_context.rb +10 -3
  35. data/lib/grape/formatters/active_model_serializers.rb +19 -2
  36. data/lib/grape/helpers/active_model_serializers.rb +1 -0
  37. data/test/action_controller/adapter_selector_test.rb +1 -1
  38. data/test/action_controller/explicit_serializer_test.rb +5 -4
  39. data/test/action_controller/json/include_test.rb +106 -27
  40. data/test/action_controller/json_api/errors_test.rb +2 -2
  41. data/test/action_controller/json_api/linked_test.rb +26 -21
  42. data/test/action_controller/serialization_test.rb +9 -6
  43. data/test/active_model_serializers/register_jsonapi_renderer_test_isolated.rb +143 -0
  44. data/test/active_model_serializers/serialization_context_test_isolated.rb +23 -10
  45. data/test/adapter/json/collection_test.rb +14 -0
  46. data/test/adapter/json_api/collection_test.rb +4 -3
  47. data/test/adapter/json_api/errors_test.rb +13 -15
  48. data/test/adapter/json_api/linked_test.rb +8 -5
  49. data/test/adapter/json_api/links_test.rb +3 -1
  50. data/test/adapter/json_api/pagination_links_test.rb +13 -1
  51. data/test/adapter/json_api/relationships_test.rb +9 -4
  52. data/test/adapter/json_api/resource_identifier_test.rb +7 -2
  53. data/test/adapter/json_api/transform_test.rb +76 -75
  54. data/test/adapter/json_test.rb +4 -3
  55. data/test/benchmark/app.rb +1 -1
  56. data/test/benchmark/bm_caching.rb +14 -14
  57. data/test/benchmark/bm_transform.rb +16 -5
  58. data/test/benchmark/controllers.rb +16 -17
  59. data/test/benchmark/fixtures.rb +72 -72
  60. data/test/cache_test.rb +73 -45
  61. data/test/fixtures/poro.rb +6 -5
  62. data/test/grape_test.rb +96 -2
  63. data/test/serializable_resource_test.rb +12 -12
  64. data/test/serializers/meta_test.rb +12 -6
  65. data/test/support/isolated_unit.rb +1 -0
  66. data/test/support/rails5_shims.rb +8 -2
  67. data/test/support/rails_app.rb +0 -9
  68. metadata +53 -23
  69. data/lib/active_model/serializer/include_tree.rb +0 -111
  70. data/test/include_tree/from_include_args_test.rb +0 -26
  71. data/test/include_tree/from_string_test.rb +0 -94
  72. data/test/include_tree/include_args_to_hash_test.rb +0 -64
@@ -136,10 +136,11 @@ AuthorSerializer = Class.new(ActiveModel::Serializer) do
136
136
  end
137
137
 
138
138
  RoleSerializer = Class.new(ActiveModel::Serializer) do
139
- cache only: [:name], skip_digest: true
140
- attributes :id, :name, :description, :slug
139
+ cache only: [:name, :slug], skip_digest: true
140
+ attributes :id, :name, :description
141
+ attribute :friendly_id, key: :slug
141
142
 
142
- def slug
143
+ def friendly_id
143
144
  "#{object.name}-#{object.id}"
144
145
  end
145
146
 
@@ -153,10 +154,10 @@ LikeSerializer = Class.new(ActiveModel::Serializer) do
153
154
  end
154
155
 
155
156
  LocationSerializer = Class.new(ActiveModel::Serializer) do
156
- cache only: [:place], skip_digest: true
157
+ cache only: [:address], skip_digest: true
157
158
  attributes :id, :lat, :lng
158
159
 
159
- belongs_to :place
160
+ belongs_to :place, key: :address
160
161
 
161
162
  def place
162
163
  'Nowhere'
@@ -1,6 +1,9 @@
1
1
  require 'test_helper'
2
2
  require 'grape'
3
3
  require 'grape/active_model_serializers'
4
+ require 'kaminari'
5
+ require 'kaminari/hooks'
6
+ ::Kaminari::Hooks.init
4
7
 
5
8
  class ActiveModelSerializers::GrapeTest < ActiveSupport::TestCase
6
9
  include Rack::Test::Methods
@@ -21,6 +24,30 @@ class ActiveModelSerializers::GrapeTest < ActiveSupport::TestCase
21
24
  ARModels::Post.all
22
25
  end
23
26
  end
27
+
28
+ def self.reset_all
29
+ ARModels::Post.delete_all
30
+ @all = nil
31
+ end
32
+
33
+ def self.collection_per
34
+ 2
35
+ end
36
+
37
+ def self.collection
38
+ @collection ||=
39
+ begin
40
+ Kaminari.paginate_array(
41
+ [
42
+ Profile.new(id: 1, name: 'Name 1', description: 'Description 1', comments: 'Comments 1'),
43
+ Profile.new(id: 2, name: 'Name 2', description: 'Description 2', comments: 'Comments 2'),
44
+ Profile.new(id: 3, name: 'Name 3', description: 'Description 3', comments: 'Comments 3'),
45
+ Profile.new(id: 4, name: 'Name 4', description: 'Description 4', comments: 'Comments 4'),
46
+ Profile.new(id: 5, name: 'Name 5', description: 'Description 5', comments: 'Comments 5')
47
+ ]
48
+ ).page(1).per(collection_per)
49
+ end
50
+ end
24
51
  end
25
52
 
26
53
  class GrapeTest < Grape::API
@@ -41,11 +68,28 @@ class ActiveModelSerializers::GrapeTest < ActiveSupport::TestCase
41
68
  posts = Models.all
42
69
  render posts, adapter: :json_api
43
70
  end
71
+
72
+ get '/render_collection_with_json_api' do
73
+ posts = Models.collection
74
+ render posts, adapter: :json_api
75
+ end
76
+
77
+ get '/render_with_implicit_formatter' do
78
+ Models.model1
79
+ end
80
+
81
+ get '/render_array_with_implicit_formatter' do
82
+ Models.all
83
+ end
84
+
85
+ get '/render_collection_with_implicit_formatter' do
86
+ Models.collection
87
+ end
44
88
  end
45
89
  end
46
90
 
47
91
  def app
48
- GrapeTest.new
92
+ Grape::Middleware::Globals.new(GrapeTest.new)
49
93
  end
50
94
 
51
95
  def test_formatter_returns_json
@@ -77,6 +121,56 @@ class ActiveModelSerializers::GrapeTest < ActiveSupport::TestCase
77
121
  assert last_response.ok?
78
122
  assert_equal serializable_resource.to_json, last_response.body
79
123
  ensure
80
- ARModels::Post.delete_all
124
+ Models.reset_all
125
+ end
126
+
127
+ def test_formatter_handles_collections
128
+ get '/grape/render_collection_with_json_api'
129
+ assert last_response.ok?
130
+
131
+ representation = JSON.parse(last_response.body)
132
+ assert representation.include?('data')
133
+ assert representation['data'].count == Models.collection_per
134
+ assert representation.include?('links')
135
+ assert representation['links'].count > 0
136
+ end
137
+
138
+ def test_implicit_formatter
139
+ post = Models.model1
140
+ serializable_resource = serializable(post, adapter: :json_api)
141
+
142
+ with_adapter :json_api do
143
+ get '/grape/render_with_implicit_formatter'
144
+ end
145
+
146
+ assert last_response.ok?
147
+ assert_equal serializable_resource.to_json, last_response.body
148
+ end
149
+
150
+ def test_implicit_formatter_handles_arrays
151
+ posts = Models.all
152
+ serializable_resource = serializable(posts, adapter: :json_api)
153
+
154
+ with_adapter :json_api do
155
+ get '/grape/render_array_with_implicit_formatter'
156
+ end
157
+
158
+ assert last_response.ok?
159
+ assert_equal serializable_resource.to_json, last_response.body
160
+ ensure
161
+ Models.reset_all
162
+ end
163
+
164
+ def test_implicit_formatter_handles_collections
165
+ with_adapter :json_api do
166
+ get '/grape/render_collection_with_implicit_formatter'
167
+ end
168
+
169
+ representation = JSON.parse(last_response.body)
170
+ assert last_response.ok?
171
+ assert representation.include?('data')
172
+ assert representation['data'].count == Models.collection_per
173
+ assert representation.include?('links')
174
+ assert representation['links'].count > 0
81
175
  end
82
176
  end
@@ -48,12 +48,12 @@ module ActiveModelSerializers
48
48
  resource, {
49
49
  serializer: ActiveModel::Serializer::ErrorSerializer,
50
50
  adapter: :json_api
51
- })
52
- expected_response_document =
53
- { :errors =>
54
- [
55
- { :source => { :pointer => '/data/attributes/name' }, :detail => 'must be awesome' }
56
- ]
51
+ }
52
+ )
53
+ expected_response_document = {
54
+ :errors => [
55
+ { :source => { :pointer => '/data/attributes/name' }, :detail => 'must be awesome' }
56
+ ]
57
57
  }
58
58
  assert_equal serializable_resource.as_json(options), expected_response_document
59
59
  end
@@ -69,12 +69,12 @@ module ActiveModelSerializers
69
69
  serializer: ActiveModel::Serializer::ErrorsSerializer,
70
70
  each_serializer: ActiveModel::Serializer::ErrorSerializer,
71
71
  adapter: :json_api
72
- })
73
- expected_response_document =
74
- { :errors =>
75
- [
76
- { :source => { :pointer => '/data/attributes/title' }, :detail => 'must be amazing' }
77
- ]
72
+ }
73
+ )
74
+ expected_response_document = {
75
+ :errors => [
76
+ { :source => { :pointer => '/data/attributes/title' }, :detail => 'must be amazing' }
77
+ ]
78
78
  }
79
79
  assert_equal serializable_resource.as_json(options), expected_response_document
80
80
  end
@@ -15,7 +15,8 @@ module ActiveModel
15
15
  @blog,
16
16
  adapter: :json,
17
17
  serializer: AlternateBlogSerializer,
18
- meta: { total: 10 }).as_json
18
+ meta: { total: 10 }
19
+ ).as_json
19
20
  expected = {
20
21
  blog: {
21
22
  id: 1,
@@ -65,7 +66,8 @@ module ActiveModel
65
66
  @blog,
66
67
  adapter: :attributes,
67
68
  serializer: AlternateBlogSerializer,
68
- meta: { total: 10 }).as_json
69
+ meta: { total: 10 }
70
+ ).as_json
69
71
  expected = {
70
72
  id: 1,
71
73
  title: 'AMS Hints'
@@ -79,7 +81,8 @@ module ActiveModel
79
81
  adapter: :json,
80
82
  serializer: AlternateBlogSerializer,
81
83
  meta: { total: 10 },
82
- meta_key: 'haha_meta').as_json
84
+ meta_key: 'haha_meta'
85
+ ).as_json
83
86
  expected = {
84
87
  blog: {
85
88
  id: 1,
@@ -98,7 +101,8 @@ module ActiveModel
98
101
  adapter: :json_api,
99
102
  serializer: AlternateBlogSerializer,
100
103
  meta: { total: 10 },
101
- meta_key: 'haha_meta').as_json
104
+ meta_key: 'haha_meta'
105
+ ).as_json
102
106
  expected = {
103
107
  data: {
104
108
  id: '1',
@@ -148,7 +152,8 @@ module ActiveModel
148
152
  actual = ActiveModelSerializers::SerializableResource.new(
149
153
  [@blog],
150
154
  adapter: :attributes,
151
- meta: { total: 10 }).as_json
155
+ meta: { total: 10 }
156
+ ).as_json
152
157
  expected = [{
153
158
  id: 1,
154
159
  name: 'AMS Hints',
@@ -170,7 +175,8 @@ module ActiveModel
170
175
  [@blog],
171
176
  adapter: :json,
172
177
  meta: { total: 10 },
173
- meta_key: 'haha_meta').as_json
178
+ meta_key: 'haha_meta'
179
+ ).as_json
174
180
  expected = {
175
181
  blogs: [{
176
182
  id: 1,
@@ -41,6 +41,7 @@ require 'active_support/core_ext/string/access'
41
41
 
42
42
  # These files do not require any others and are needed
43
43
  # to run the tests
44
+ require 'active_support/testing/autorun'
44
45
  require 'active_support/testing/isolation'
45
46
 
46
47
  module TestHelpers
@@ -1,7 +1,7 @@
1
1
  module Rails5Shims
2
2
  module ControllerTests
3
3
  # https://github.com/rails/rails/blob/b217354/actionpack/lib/action_controller/test_case.rb
4
- REQUEST_KWARGS = [:params, :session, :flash, :method, :body, :xhr].freeze
4
+ REQUEST_KWARGS = [:params, :headers, :session, :flash, :method, :body, :xhr].freeze
5
5
 
6
6
  def get(path, *args)
7
7
  fold_kwargs!(args)
@@ -30,7 +30,12 @@ module Rails5Shims
30
30
  return unless hash.respond_to?(:key)
31
31
  Rails5Shims::ControllerTests::REQUEST_KWARGS.each do |kwarg|
32
32
  next unless hash.key?(kwarg)
33
- hash.merge! hash.delete(kwarg)
33
+ value = hash.delete(kwarg)
34
+ if value.is_a? String
35
+ args.insert(0, value)
36
+ else
37
+ hash.merge! value
38
+ end
34
39
  end
35
40
  end
36
41
 
@@ -44,4 +49,5 @@ module Rails5Shims
44
49
  end
45
50
  if Rails::VERSION::MAJOR < 5
46
51
  ActionController::TestCase.send :include, Rails5Shims::ControllerTests
52
+ ActionDispatch::IntegrationTest.send :include, Rails5Shims::ControllerTests
47
53
  end
@@ -22,15 +22,6 @@ ActionController::TestCase.class_eval do
22
22
  def setup
23
23
  @routes = Routes
24
24
  end
25
-
26
- # For Rails5
27
- # https://github.com/rails/rails/commit/ca83436d1b3b6cedd1eca2259f65661e69b01909#diff-b9bbf56e85d3fe1999f16317f2751e76L17
28
- def assigns(key = nil)
29
- warn "DEPRECATION: Calling 'assigns(#{key})' from #{caller[0]}"
30
- assigns = {}.with_indifferent_access
31
- @controller.view_assigns.each { |k, v| assigns.regular_writer(k, v) }
32
- key.nil? ? assigns : assigns[key]
33
- end
34
25
  end
35
26
 
36
27
  # ActiveRecord::Migrator.migrations_paths = [File.expand_path("../../test/dummy/db/migrate", __FILE__)]
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_model_serializers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.10.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Klabnik
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-17 00:00:00.000000000 Z
11
+ date: 2016-06-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -16,56 +16,94 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '4.0'
19
+ version: '4.1'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '6'
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
27
  - - ">="
25
28
  - !ruby/object:Gem::Version
26
- version: '4.0'
29
+ version: '4.1'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '6'
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: actionpack
29
35
  requirement: !ruby/object:Gem::Requirement
30
36
  requirements:
31
37
  - - ">="
32
38
  - !ruby/object:Gem::Version
33
- version: '4.0'
39
+ version: '4.1'
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '6'
34
43
  type: :runtime
35
44
  prerelease: false
36
45
  version_requirements: !ruby/object:Gem::Requirement
37
46
  requirements:
38
47
  - - ">="
39
48
  - !ruby/object:Gem::Version
40
- version: '4.0'
49
+ version: '4.1'
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '6'
41
53
  - !ruby/object:Gem::Dependency
42
54
  name: railties
43
55
  requirement: !ruby/object:Gem::Requirement
44
56
  requirements:
45
57
  - - ">="
46
58
  - !ruby/object:Gem::Version
47
- version: '4.0'
59
+ version: '4.1'
60
+ - - "<"
61
+ - !ruby/object:Gem::Version
62
+ version: '6'
48
63
  type: :runtime
49
64
  prerelease: false
50
65
  version_requirements: !ruby/object:Gem::Requirement
51
66
  requirements:
52
67
  - - ">="
53
68
  - !ruby/object:Gem::Version
54
- version: '4.0'
69
+ version: '4.1'
70
+ - - "<"
71
+ - !ruby/object:Gem::Version
72
+ version: '6'
73
+ - !ruby/object:Gem::Dependency
74
+ name: jsonapi
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: 0.1.1.beta2
80
+ type: :runtime
81
+ prerelease: false
82
+ version_requirements: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - "~>"
85
+ - !ruby/object:Gem::Version
86
+ version: 0.1.1.beta2
55
87
  - !ruby/object:Gem::Dependency
56
88
  name: activerecord
57
89
  requirement: !ruby/object:Gem::Requirement
58
90
  requirements:
59
91
  - - ">="
60
92
  - !ruby/object:Gem::Version
61
- version: '4.0'
93
+ version: '4.1'
94
+ - - "<"
95
+ - !ruby/object:Gem::Version
96
+ version: '6'
62
97
  type: :development
63
98
  prerelease: false
64
99
  version_requirements: !ruby/object:Gem::Requirement
65
100
  requirements:
66
101
  - - ">="
67
102
  - !ruby/object:Gem::Version
68
- version: '4.0'
103
+ version: '4.1'
104
+ - - "<"
105
+ - !ruby/object:Gem::Version
106
+ version: '6'
69
107
  - !ruby/object:Gem::Dependency
70
108
  name: kaminari
71
109
  requirement: !ruby/object:Gem::Requirement
@@ -274,7 +312,6 @@ files:
274
312
  - lib/active_model/serializer/fieldset.rb
275
313
  - lib/active_model/serializer/has_many_reflection.rb
276
314
  - lib/active_model/serializer/has_one_reflection.rb
277
- - lib/active_model/serializer/include_tree.rb
278
315
  - lib/active_model/serializer/links.rb
279
316
  - lib/active_model/serializer/lint.rb
280
317
  - lib/active_model/serializer/meta.rb
@@ -335,6 +372,7 @@ files:
335
372
  - test/active_model_serializers/logging_test.rb
336
373
  - test/active_model_serializers/model_test.rb
337
374
  - test/active_model_serializers/railtie_test_isolated.rb
375
+ - test/active_model_serializers/register_jsonapi_renderer_test_isolated.rb
338
376
  - test/active_model_serializers/serialization_context_test_isolated.rb
339
377
  - test/active_model_serializers/test/schema_test.rb
340
378
  - test/active_model_serializers/test/serializer_test.rb
@@ -383,9 +421,6 @@ files:
383
421
  - test/generators/scaffold_controller_generator_test.rb
384
422
  - test/generators/serializer_generator_test.rb
385
423
  - test/grape_test.rb
386
- - test/include_tree/from_include_args_test.rb
387
- - test/include_tree/from_string_test.rb
388
- - test/include_tree/include_args_to_hash_test.rb
389
424
  - test/lint_test.rb
390
425
  - test/logger_test.rb
391
426
  - test/poro_test.rb
@@ -419,10 +454,7 @@ homepage: https://github.com/rails-api/active_model_serializers
419
454
  licenses:
420
455
  - MIT
421
456
  metadata: {}
422
- post_install_message: |
423
- NOTE: The default key case for the JsonApi adapter has changed to dashed.
424
- See https://github.com/rails-api/active_model_serializers/blob/master/docs/general/key_transforms.md
425
- for more information on configuring this behavior.
457
+ post_install_message:
426
458
  rdoc_options: []
427
459
  require_paths:
428
460
  - lib
@@ -430,7 +462,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
430
462
  requirements:
431
463
  - - ">="
432
464
  - !ruby/object:Gem::Version
433
- version: 2.0.0
465
+ version: '2.1'
434
466
  required_rubygems_version: !ruby/object:Gem::Requirement
435
467
  requirements:
436
468
  - - ">="
@@ -438,7 +470,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
438
470
  version: '0'
439
471
  requirements: []
440
472
  rubyforge_project:
441
- rubygems_version: 2.4.5
473
+ rubygems_version: 2.4.8
442
474
  signing_key:
443
475
  specification_version: 4
444
476
  summary: Conventions-based JSON generation for Rails.
@@ -459,6 +491,7 @@ test_files:
459
491
  - test/active_model_serializers/logging_test.rb
460
492
  - test/active_model_serializers/model_test.rb
461
493
  - test/active_model_serializers/railtie_test_isolated.rb
494
+ - test/active_model_serializers/register_jsonapi_renderer_test_isolated.rb
462
495
  - test/active_model_serializers/serialization_context_test_isolated.rb
463
496
  - test/active_model_serializers/test/schema_test.rb
464
497
  - test/active_model_serializers/test/serializer_test.rb
@@ -507,9 +540,6 @@ test_files:
507
540
  - test/generators/scaffold_controller_generator_test.rb
508
541
  - test/generators/serializer_generator_test.rb
509
542
  - test/grape_test.rb
510
- - test/include_tree/from_include_args_test.rb
511
- - test/include_tree/from_string_test.rb
512
- - test/include_tree/include_args_to_hash_test.rb
513
543
  - test/lint_test.rb
514
544
  - test/logger_test.rb
515
545
  - test/poro_test.rb