daylight 0.9.0.rc1

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 (116) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +113 -0
  3. data/app/controllers/daylight_documentation/documentation_controller.rb +27 -0
  4. data/app/helpers/daylight_documentation/documentation_helper.rb +57 -0
  5. data/app/views/daylight_documentation/documentation/_header.haml +4 -0
  6. data/app/views/daylight_documentation/documentation/index.haml +12 -0
  7. data/app/views/daylight_documentation/documentation/model.haml +114 -0
  8. data/app/views/layouts/documentation.haml +22 -0
  9. data/config/routes.rb +8 -0
  10. data/doc/actions.md +70 -0
  11. data/doc/benchmarks.md +17 -0
  12. data/doc/contribute.md +80 -0
  13. data/doc/develop.md +1205 -0
  14. data/doc/environment.md +109 -0
  15. data/doc/example.md +3 -0
  16. data/doc/framework.md +31 -0
  17. data/doc/install.md +128 -0
  18. data/doc/principles.md +42 -0
  19. data/doc/testing.md +107 -0
  20. data/doc/usage.md +970 -0
  21. data/lib/daylight/api.rb +293 -0
  22. data/lib/daylight/associations.rb +247 -0
  23. data/lib/daylight/client_reloader.rb +45 -0
  24. data/lib/daylight/collection.rb +161 -0
  25. data/lib/daylight/errors.rb +94 -0
  26. data/lib/daylight/inflections.rb +7 -0
  27. data/lib/daylight/mock.rb +282 -0
  28. data/lib/daylight/read_only.rb +88 -0
  29. data/lib/daylight/refinements.rb +63 -0
  30. data/lib/daylight/reflection_ext.rb +67 -0
  31. data/lib/daylight/resource_proxy.rb +226 -0
  32. data/lib/daylight/version.rb +10 -0
  33. data/lib/daylight.rb +27 -0
  34. data/rails/daylight/api_controller.rb +354 -0
  35. data/rails/daylight/documentation.rb +13 -0
  36. data/rails/daylight/helpers.rb +32 -0
  37. data/rails/daylight/params.rb +23 -0
  38. data/rails/daylight/refiners.rb +186 -0
  39. data/rails/daylight/server.rb +29 -0
  40. data/rails/daylight/tasks.rb +37 -0
  41. data/rails/extensions/array_ext.rb +9 -0
  42. data/rails/extensions/autosave_association_fix.rb +49 -0
  43. data/rails/extensions/has_one_serializer_ext.rb +111 -0
  44. data/rails/extensions/inflections.rb +6 -0
  45. data/rails/extensions/nested_attributes_ext.rb +94 -0
  46. data/rails/extensions/read_only_attributes.rb +35 -0
  47. data/rails/extensions/render_json_meta.rb +99 -0
  48. data/rails/extensions/route_options.rb +47 -0
  49. data/rails/extensions/versioned_url_for.rb +22 -0
  50. data/spec/config/dependencies.rb +2 -0
  51. data/spec/config/factory_girl.rb +4 -0
  52. data/spec/config/simplecov_rcov.rb +26 -0
  53. data/spec/config/test_api.rb +1 -0
  54. data/spec/controllers/documentation_controller_spec.rb +24 -0
  55. data/spec/dummy/README.rdoc +28 -0
  56. data/spec/dummy/Rakefile +6 -0
  57. data/spec/dummy/app/assets/images/.keep +0 -0
  58. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  59. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  60. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  61. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  62. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  63. data/spec/dummy/app/mailers/.keep +0 -0
  64. data/spec/dummy/app/models/.keep +0 -0
  65. data/spec/dummy/app/models/concerns/.keep +0 -0
  66. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  67. data/spec/dummy/bin/bundle +3 -0
  68. data/spec/dummy/bin/rails +4 -0
  69. data/spec/dummy/bin/rake +4 -0
  70. data/spec/dummy/config/application.rb +24 -0
  71. data/spec/dummy/config/boot.rb +5 -0
  72. data/spec/dummy/config/database.yml +25 -0
  73. data/spec/dummy/config/environment.rb +5 -0
  74. data/spec/dummy/config/environments/development.rb +29 -0
  75. data/spec/dummy/config/environments/production.rb +80 -0
  76. data/spec/dummy/config/environments/test.rb +36 -0
  77. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  78. data/spec/dummy/config/initializers/daylight.rb +1 -0
  79. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  80. data/spec/dummy/config/initializers/inflections.rb +16 -0
  81. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  82. data/spec/dummy/config/initializers/secret_token.rb +12 -0
  83. data/spec/dummy/config/initializers/session_store.rb +3 -0
  84. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  85. data/spec/dummy/config/locales/en.yml +23 -0
  86. data/spec/dummy/config/routes.rb +59 -0
  87. data/spec/dummy/config.ru +4 -0
  88. data/spec/dummy/lib/assets/.keep +0 -0
  89. data/spec/dummy/log/.keep +0 -0
  90. data/spec/dummy/public/404.html +58 -0
  91. data/spec/dummy/public/422.html +58 -0
  92. data/spec/dummy/public/500.html +57 -0
  93. data/spec/dummy/public/favicon.ico +0 -0
  94. data/spec/helpers/documentation_helper_spec.rb +82 -0
  95. data/spec/lib/daylight/api_spec.rb +178 -0
  96. data/spec/lib/daylight/associations_spec.rb +325 -0
  97. data/spec/lib/daylight/collection_spec.rb +235 -0
  98. data/spec/lib/daylight/errors_spec.rb +111 -0
  99. data/spec/lib/daylight/mock_spec.rb +144 -0
  100. data/spec/lib/daylight/read_only_spec.rb +118 -0
  101. data/spec/lib/daylight/refinements_spec.rb +80 -0
  102. data/spec/lib/daylight/reflection_ext_spec.rb +50 -0
  103. data/spec/lib/daylight/resource_proxy_spec.rb +325 -0
  104. data/spec/rails/daylight/api_controller_spec.rb +421 -0
  105. data/spec/rails/daylight/helpers_spec.rb +41 -0
  106. data/spec/rails/daylight/params_spec.rb +45 -0
  107. data/spec/rails/daylight/refiners_spec.rb +178 -0
  108. data/spec/rails/extensions/array_ext_spec.rb +51 -0
  109. data/spec/rails/extensions/has_one_serializer_ext_spec.rb +135 -0
  110. data/spec/rails/extensions/nested_attributes_ext_spec.rb +177 -0
  111. data/spec/rails/extensions/render_json_meta_spec.rb +140 -0
  112. data/spec/rails/extensions/route_options_spec.rb +309 -0
  113. data/spec/rails/extensions/versioned_url_for_spec.rb +46 -0
  114. data/spec/spec_helper.rb +43 -0
  115. data/spec/support/migration_helper.rb +40 -0
  116. metadata +422 -0
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ class NonExtractableTest < Hash; end
4
+
5
+ class IsExtractableTest < Hash
6
+ def extractable_options?
7
+ true
8
+ end
9
+ end
10
+
11
+ describe Array do
12
+ describe :extract_options do
13
+ it 'returns options' do
14
+ [foo: 'bar'].extract_options.should == {foo: 'bar'}
15
+ ['a', foo: 'bar'].extract_options.should == {foo: 'bar'}
16
+ end
17
+
18
+ it 'returns empty hash when no options' do
19
+ [].extract_options.should == {}
20
+ ['a', 'b'].extract_options.should == {}
21
+ end
22
+
23
+ it 'returns empty hash when not extractable' do
24
+ hash = NonExtractableTest.new
25
+ hash[:foo] = 'bar'
26
+ [hash].extract_options.should == {}
27
+ end
28
+
29
+ it 'returns extractable hash when extractable' do
30
+ test = IsExtractableTest.new
31
+ test[:foo] = 'bar'
32
+ [test].extract_options.should == test
33
+ end
34
+
35
+ it 'leaves options on arguments' do
36
+ hash = [foo: 'bar']
37
+ hash.extract_options
38
+ hash.should == [foo: 'bar']
39
+
40
+ hash = ['a', foo: 'bar']
41
+ hash.extract_options
42
+ hash.should == ['a', foo: 'bar']
43
+
44
+ test = IsExtractableTest.new
45
+ test[:foo] = 'bar'
46
+ hash = [test]
47
+ hash.extract_options
48
+ hash.should == [test]
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,135 @@
1
+ require 'spec_helper'
2
+
3
+ class HasOneSerializerTest < ActiveRecord::Base
4
+ belongs_to :associated_test
5
+ has_one :associated_through_test, through: :associated_test
6
+ end
7
+
8
+ class AssociatedTest < ActiveRecord::Base
9
+ belongs_to :associated_through_test
10
+ end
11
+
12
+ class AssociatedThroughTest < ActiveRecord::Base
13
+ end
14
+
15
+ class HasOneSerializerTestController < ActionController::Base
16
+ # The read_only values will be activated based on Serializer
17
+ def show
18
+ render json: HasOneSerializerTest.find(params[:id])
19
+ end
20
+
21
+ def embed
22
+ render json: HasOneSerializerTest.find(params[:id]),
23
+ serializer: EmbedHasOneSerializerTestSerializer
24
+ end
25
+ end
26
+
27
+ class HasOneSerializerTestSerializer < ActiveModel::Serializer
28
+ embed :ids
29
+
30
+ has_one :associated_test # tests orginal
31
+ has_one :associated_through_test, through: :associated_test # tests through
32
+ end
33
+
34
+ class EmbedHasOneSerializerTestSerializer < ActiveModel::Serializer
35
+ has_one :associated_test # tests orginal
36
+ has_one :associated_through_test, through: :associated_test # tests through
37
+ end
38
+
39
+ describe HasOneSerializerExt, type: [:controller, :routing] do
40
+
41
+ def self.controller_class
42
+ HasOneSerializerTestController
43
+ end
44
+
45
+ migrate do
46
+ create_table :has_one_serializer_tests do |t|
47
+ t.integer :associated_test_id
48
+ end
49
+
50
+ create_table :associated_tests do |t|
51
+ t.integer :associated_through_test_id
52
+ end
53
+
54
+ create_table :associated_through_tests do |t|
55
+ t.string :name
56
+ end
57
+ end
58
+
59
+ before do
60
+ @routes.draw do
61
+ resources :has_one_serializer_test do
62
+ get 'embed', on: :member
63
+ end
64
+ end
65
+ end
66
+
67
+ before :all do
68
+ FactoryGirl.define do
69
+ factory :has_one_serializer_test do
70
+ associated_test
71
+ end
72
+
73
+ factory :associated_test do
74
+ associated_through_test
75
+ end
76
+
77
+ factory :associated_through_test do
78
+ name { Faker::Name.name }
79
+ end
80
+ end
81
+ end
82
+
83
+ after :all do
84
+ Rails.application.reload_routes!
85
+ end
86
+
87
+ let!(:record) { create(:has_one_serializer_test) }
88
+
89
+ #
90
+ # embed id
91
+ #
92
+
93
+ it 'includes association id' do
94
+ get :show, id: record.id
95
+
96
+ json = JSON.parse(response.body)['has_one_serializer_test']
97
+ json['associated_test_id'].should == record.associated_test_id
98
+ json.keys.should_not include('associated_through_test_id')
99
+ end
100
+
101
+ it 'includes through association hash with ids' do
102
+ get :show, id: record.id
103
+
104
+ json = JSON.parse(response.body)['has_one_serializer_test']
105
+ json['associated_test_attributes'].should == {
106
+ 'id' => record.associated_test.id,
107
+ 'associated_through_test_id' => record.associated_test.associated_through_test_id
108
+ }
109
+ end
110
+
111
+ #
112
+ # embed object
113
+ #
114
+
115
+ it 'includes association' do
116
+ get :embed, id: record.id
117
+
118
+ json = JSON.parse(response.body)['embed_has_one_serializer_test']
119
+ json['associated_test'].should == record.associated_test.attributes
120
+ end
121
+
122
+ it 'includes association hash' do
123
+ get :embed, id: record.id
124
+
125
+ json = JSON.parse(response.body)['embed_has_one_serializer_test']
126
+ json['associated_test_attributes'].should == {
127
+ 'id' => record.associated_test.id,
128
+ 'associated_through_test_id' => record.associated_test.associated_through_test_id,
129
+ 'associated_through_test_attributes' => {
130
+ 'id' => record.associated_test.associated_through_test.id,
131
+ 'name' => record.associated_test.associated_through_test.name,
132
+ }
133
+ }
134
+ end
135
+ end
@@ -0,0 +1,177 @@
1
+ require 'spec_helper'
2
+
3
+ class NoNestedAttributesTest < ActiveRecord::Base; end
4
+
5
+ # `inverse_of` and `accepts_nested_attributes_for` both need to be defined to
6
+ # test cyclic autosave problem that AutosaveAssociataionFix resolves
7
+ class NestedAttributeTest < ActiveRecord::Base
8
+ has_many :collection, class_name: 'AssocNestedAttributeTest', inverse_of: :nested_attribute_test
9
+
10
+ accepts_nested_attributes_for :collection
11
+ end
12
+
13
+ class SingleNestedAttributeTest < ActiveRecord::Base
14
+ has_one :single, class_name: 'AssocNestedAttributeTest', inverse_of: :single_nested_attribute_test
15
+
16
+ accepts_nested_attributes_for :single, allow_destroy: true # with options
17
+ end
18
+
19
+ class AssocNestedAttributeTest < ActiveRecord::Base
20
+ belongs_to :nested_attribute_test, inverse_of: :collection
21
+ belongs_to :single_nested_attribute_test, inverse_of: :single
22
+
23
+ accepts_nested_attributes_for :nested_attribute_test, :single_nested_attribute_test
24
+ end
25
+
26
+ describe NestedAttributesExt, type: [:model] do
27
+
28
+ migrate do
29
+ create_table :nested_attribute_tests do |t|
30
+ t.string :name
31
+ end
32
+
33
+ create_table :single_nested_attribute_tests do |t|
34
+ t.string :name
35
+ end
36
+
37
+ create_table :assoc_nested_attribute_tests do |t|
38
+ t.string :name
39
+ t.references :nested_attribute_test
40
+ t.references :single_nested_attribute_test
41
+ end
42
+ end
43
+
44
+ before(:all) do
45
+ FactoryGirl.define do
46
+ factory :nested_attribute_test do
47
+ name { Faker::Name.name }
48
+ end
49
+
50
+ factory :single_nested_attribute_test do
51
+ name { Faker::Name.name }
52
+ end
53
+
54
+ factory :assoc_nested_attribute_test do
55
+ name { Faker::Name.name }
56
+ end
57
+ end
58
+ end
59
+
60
+ describe 'nested_resource_names' do
61
+ it 'has empty array of no nested resources are configured' do
62
+ NoNestedAttributesTest.nested_resource_names.should == []
63
+ NoNestedAttributesTest.nested_resource_names.should be_frozen
64
+ end
65
+
66
+ it 'stores only nested resource names' do
67
+ SingleNestedAttributeTest.nested_resource_names.should == [:single]
68
+ SingleNestedAttributeTest.nested_resource_names.should be_frozen
69
+
70
+ AssocNestedAttributeTest.nested_resource_names.should == [:nested_attribute_test, :single_nested_attribute_test]
71
+ AssocNestedAttributeTest.nested_resource_names.should be_frozen
72
+ end
73
+
74
+ it 'propogates and updates nested attribute options' do
75
+ SingleNestedAttributeTest.nested_attributes_options.should == {single: {allow_destroy: true, update_only: false}}
76
+ end
77
+ end
78
+
79
+
80
+ describe 'has_many' do
81
+ let(:record) { create(:nested_attribute_test) }
82
+ let(:member) { create(:assoc_nested_attribute_test) }
83
+
84
+ it "ignores nil values" do
85
+ record.collection_attributes = nil
86
+
87
+ lambda { record.save! }.should_not raise_error
88
+ record.collection.should == []
89
+ end
90
+
91
+ it "continues to create and associate new records" do
92
+ record.collection_attributes = [{name: 'foo'}, {name: 'bar'}]
93
+
94
+ lambda { record.save! }.should_not raise_error
95
+
96
+ names = record.collection.map(&:name)
97
+ names.should include('foo')
98
+ names.should include('bar')
99
+ end
100
+
101
+ it "continues to update assoicated records" do
102
+ record.collection << member
103
+ record.collection_attributes = [{id: member.id, name: 'Foozle Cumberbunch'}]
104
+
105
+ lambda { record.save! }.should_not raise_error
106
+ record.collection.size.should == 1
107
+ record.collection.first.name.should == 'Foozle Cumberbunch'
108
+ end
109
+
110
+ # this also tests cyclic autosave problem that AutosaveAssociataionFix resolves
111
+ it "associates existing records" do
112
+ record.collection_attributes = [{id: member.id}]
113
+
114
+ lambda { record.save! }.should_not raise_error
115
+ record.collection.size.should == 1
116
+ record.collection.first.id.should == member.id
117
+ end
118
+
119
+ # this also tests cyclic autosave problem that AutosaveAssociataionFix resolves
120
+ it "keeps association for existing records that are already assoicated" do
121
+ record.collection << member
122
+ record.collection_attributes = [{id: member.id}]
123
+
124
+ lambda { record.save! }.should_not raise_error
125
+ record.collection.size.should == 1
126
+ record.collection.first.id.should == member.id
127
+ end
128
+
129
+ it "updates records that were just associated" do
130
+ record.collection_attributes = [{id: member.id, name: 'Foozle Cumberbunch'}]
131
+
132
+ lambda { record.save! }.should_not raise_error
133
+ record.collection.size.should == 1
134
+ record.collection.first.name.should == 'Foozle Cumberbunch'
135
+ end
136
+
137
+ it "ignores foreign key updates" do
138
+ different_foreign_key = record.id + 1
139
+ record.collection_attributes = [{id: member.id, name: 'Foozle Cumberbunch', nested_attribute_test_id: different_foreign_key}]
140
+
141
+ lambda { record.save! }.should_not raise_error
142
+
143
+ record.collection.size.should == 1
144
+ record.collection.first.nested_attribute_test_id.should == record.id
145
+ end
146
+
147
+ # this also tests cyclic autosave problem that AutosaveAssociataionFix resolves
148
+ it "updates previsoulsy associated records" do
149
+ record.collection << member
150
+
151
+ lambda { record.update!(collection_attributes: [{id: member.id, name: 'Foozle Cumberbunch'}]) }.should_not raise_error
152
+
153
+ record.collection.size.should == 1
154
+ record.collection.first.name.should == 'Foozle Cumberbunch'
155
+ end
156
+ end
157
+
158
+ describe 'has_one' do
159
+ let(:record) { create(:single_nested_attribute_test) }
160
+ let(:member) { create(:assoc_nested_attribute_test) }
161
+
162
+ it "ignores nil values" do
163
+ record.single = nil
164
+
165
+ lambda { record.save! }.should_not raise_error
166
+ record.single.should be_nil
167
+ end
168
+
169
+ it "continues to create and associate new records" do
170
+ record.single_attributes = {name: 'wibble'}
171
+
172
+ lambda { record.save! }.should_not raise_error
173
+
174
+ record.single.name.should == 'wibble'
175
+ end
176
+ end
177
+ end
@@ -0,0 +1,140 @@
1
+ require 'spec_helper'
2
+
3
+ class AssociatedRenderJsonMetaTest < ActiveRecord::Base
4
+ end
5
+
6
+ class RenderJsonMetaTest < ActiveRecord::Base
7
+ has_many :children, class_name: 'AssociatedRenderJsonMetaTest'
8
+
9
+ accepts_nested_attributes_for :children
10
+ end
11
+
12
+ # this implicitly tests read_only attributes
13
+ class RenderJsonMetaTestSerializer < ActiveModel::Serializer
14
+ read_only :name, :valid?
15
+
16
+ def valid?; true; end
17
+ end
18
+
19
+ class RenderJsonMetaTestController < ActionController::Base
20
+ # The read_only values will be activated based on Serializer
21
+ def index
22
+ render json: RenderJsonMetaTest.all
23
+ end
24
+
25
+ def show
26
+ render json: RenderJsonMetaTest.find(params[:id])
27
+ end
28
+
29
+ # AssociatonRelation will activate where_values
30
+ def associated
31
+ render json: RenderJsonMetaTest.find(params[:id]).children.where(name: params[:name])
32
+ end
33
+
34
+ def child
35
+ render json: AssociatedRenderJsonMetaTest.find(params[:id])
36
+ end
37
+ end
38
+
39
+ describe RenderJsonMeta, type: [:controller, :routing] do
40
+
41
+ def self.controller_class
42
+ RenderJsonMetaTestController
43
+ end
44
+
45
+ migrate do
46
+ create_table :render_json_meta_tests do |t|
47
+ t.string :name
48
+ end
49
+
50
+ create_table :associated_render_json_meta_tests do |t|
51
+ t.string :name
52
+ t.integer :render_json_meta_test_id
53
+ end
54
+ end
55
+
56
+ before do
57
+ @routes.draw do
58
+ resources :render_json_meta_test do
59
+ get 'associated', on: :member
60
+ get 'child', on: :member
61
+ end
62
+ end
63
+ end
64
+
65
+ before :all do
66
+ FactoryGirl.define do
67
+ factory :render_json_meta_test do
68
+ name { Faker::Name.name }
69
+ end
70
+
71
+ factory :associated_render_json_meta_test do
72
+ name { Faker::Name.name }
73
+ end
74
+ end
75
+ end
76
+
77
+ after :all do
78
+ Rails.application.reload_routes!
79
+ end
80
+
81
+ let!(:record1) { create(:render_json_meta_test) }
82
+ let!(:record2) { create(:render_json_meta_test) }
83
+ let!(:associated) { create(:associated_render_json_meta_test, render_json_meta_test_id: record1.id) }
84
+
85
+ describe "read_only" do
86
+ it 'renders on record' do
87
+ get :show, id: record1.id
88
+
89
+ # tests for no '?' on valid in both the attribute and read_only names
90
+ json = JSON.parse(response.body)
91
+ json['render_json_meta_test'].keys.should include('valid')
92
+ json['meta']['render_json_meta_test'].should include({'read_only' => ['name', 'valid']})
93
+ end
94
+
95
+ it 'renders on collection' do
96
+ get :index
97
+
98
+ json = JSON.parse(response.body)
99
+ json['meta']['render_json_meta_test'].should include({'read_only' => ['name', 'valid'] })
100
+ end
101
+
102
+ it 'renders no metadata' do
103
+ get :child, id: associated.id
104
+
105
+ json = JSON.parse(response.body)
106
+ json.keys.should_not include('meta')
107
+ end
108
+ end
109
+
110
+ describe "nested_resources" do
111
+ it 'renders on record' do
112
+ get :show, id: record1.id
113
+
114
+ # tests for no '?' on valid in both the attribute and read_only names
115
+ json = JSON.parse(response.body)
116
+ json['meta']['render_json_meta_test'].should include({'nested_resources' => ['children']})
117
+ end
118
+
119
+ it 'renders on collection' do
120
+ get :index
121
+
122
+ json = JSON.parse(response.body)
123
+ json['meta']['render_json_meta_test'].should include({'nested_resources' => ['children']})
124
+ end
125
+
126
+ it 'renders no metadata' do
127
+ get :child, id: associated.id
128
+
129
+ json = JSON.parse(response.body)
130
+ json.keys.should_not include('meta')
131
+ end
132
+ end
133
+
134
+ it 'renders where_values' do
135
+ get :associated, id: record1.id, name: associated.name
136
+
137
+ json = JSON.parse(response.body)
138
+ json['meta']['where_values'].should == {'render_json_meta_test_id' => associated.render_json_meta_test_id , 'name' => associated.name }
139
+ end
140
+ end