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,144 @@
1
+ require 'spec_helper'
2
+ require 'daylight/mock'
3
+
4
+ describe Daylight::Mock do
5
+ class MiniTest::Spec ; end
6
+ class MiniTest::Test ; end
7
+
8
+ class TestClient < Daylight::API
9
+ has_many :test_client_children, through: :associated, class_name: 'TestClientChild'
10
+ end
11
+
12
+ class TestClientChild < Daylight::API ; end
13
+
14
+ # All clients will do this in their spec_helper.rb/test_helper.rb
15
+ Daylight::Mock.setup
16
+
17
+ describe 'return values' do
18
+ describe 'show' do
19
+ it "returns a single object of the correct type" do
20
+ TestClient.find(1).should be_instance_of(TestClient)
21
+ end
22
+
23
+ it "has the correct ID" do
24
+ TestClient.find(1).id.should == 1
25
+ end
26
+ end
27
+
28
+ describe 'index' do
29
+ it "returns a list of objects of the correct type" do
30
+ results = TestClient.find(:all)
31
+ results.should respond_to(:size)
32
+ results.first.should be_instance_of(TestClient)
33
+ end
34
+
35
+ it "seeds the objects with ids" do
36
+ TestClient.find(:all).all? {|z| z.id.present? }.should be_true
37
+ end
38
+
39
+ it "seeds the objects with any filters" do
40
+ TestClient.where(foo: 'bar').all? {|z| z.foo == 'bar' }.should be_true
41
+ end
42
+ end
43
+
44
+ describe 'associated' do
45
+ it "returns a list of objects of the associated type" do
46
+ results = TestClient.find(1).test_client_children
47
+ results.should respond_to(:size)
48
+ results.first.should be_instance_of(TestClientChild)
49
+ end
50
+
51
+ it "seeds the responses with ids" do
52
+ TestClient.find(1).test_client_children.all? {|z| z.id.present? }.should be_true
53
+ end
54
+
55
+ it "seeds the objects with any filters" do
56
+ TestClient.find(1).test_client_children.where(foo: 'bar').all? {|z| z.foo == 'bar' }.should be_true
57
+ end
58
+ end
59
+
60
+ describe 'update' do
61
+ it "returns a new object with the updated attributes" do
62
+ object = TestClient.find(1)
63
+ object.update_attributes(name: 'wibble').should be_true
64
+ end
65
+ end
66
+
67
+ describe 'create' do
68
+ it "returns the created object" do
69
+ object = TestClient.new(name: 'foo')
70
+ object.name = 'foo'
71
+ object.save.should be_true
72
+ object.id.should_not be_nil
73
+ end
74
+ end
75
+
76
+ describe 'destroy' do
77
+ it "returns a new object with the updated attributes" do
78
+ object = TestClient.find(1)
79
+ object.destroy.should be_true
80
+ end
81
+ end
82
+ end
83
+
84
+ describe 'recorder' do
85
+ it "keeps track of call counts across actions" do
86
+ TestClient.find(123)
87
+ TestClient.find(456)
88
+
89
+ daylight_mock.shown(:test_clients).count.should == 2
90
+ end
91
+
92
+ it "keeps track of the requests" do
93
+ TestClient.find(:all)
94
+
95
+ daylight_mock.indexed(:test_client).first.request.method.should == :get
96
+ end
97
+
98
+ it "keeps track of the responses" do
99
+ object = TestClient.find(1)
100
+ object.update_attributes(name: 'wibble')
101
+
102
+ daylight_mock.updated(:test_client).first.status.should == 201
103
+ end
104
+
105
+ it "returns the last response" do
106
+ TestClient.find(123)
107
+ TestClient.find(456)
108
+
109
+ daylight_mock.last_shown(:test_clients).response.id.should == 456
110
+ end
111
+
112
+ describe :target_object do
113
+ it "sets the target_object value for examination on update" do
114
+ object = TestClient.find(1)
115
+ object.update_attributes(code: 'wibble')
116
+
117
+ daylight_mock.last_updated(:test_clients).target_object.code.should == 'wibble'
118
+ end
119
+
120
+ it "sets the target_object value for examination on create" do
121
+ object = TestClient.new(code: 'foo')
122
+ object.name = 'foo'
123
+ object.save.should be_true
124
+
125
+ daylight_mock.last_created(:test_clients).target_object.code.should == 'foo'
126
+ end
127
+ end
128
+
129
+ end
130
+
131
+ describe 'minitest setup' do
132
+ let(:minitest) { Minitest::Test.new }
133
+
134
+ it "adds our mock methods to Minitest::Test" do
135
+ minitest.should respond_to(:daylight_mock)
136
+ end
137
+
138
+ it "captures API requests" do
139
+ minitest.should_receive(:stub_request).and_return stub_request(:any, /.*/)
140
+ minitest.before_setup
141
+ end
142
+ end
143
+
144
+ end
@@ -0,0 +1,118 @@
1
+ require 'spec_helper'
2
+
3
+ class TestReadOnly < Daylight::API
4
+ self.password = nil
5
+
6
+ has_one :child, class_name: 'TestReadOnly'
7
+ end
8
+
9
+ describe Daylight::ReadOnly do
10
+ def parse_xml(xml)
11
+ data = Hash.from_xml(xml)
12
+
13
+ if data.is_a?(Hash) && data.keys.size == 1
14
+ data.values.first
15
+ else
16
+ data
17
+ end
18
+ end
19
+
20
+ describe "read only attributes" do
21
+ before do
22
+ data = {
23
+ test_read_only: { name: "foo", immutable: "readme"},
24
+ meta: { test_read_only: { read_only: ["immutable"], nested_resources: ["test_resource"] } }
25
+ }
26
+
27
+ stub_request(:any, %r{#{TestReadOnly.site}}).to_return(body: data.to_json)
28
+ end
29
+
30
+ it "is defined" do
31
+ test = TestReadOnly.find(1)
32
+
33
+ test.read_only.should == ["immutable"]
34
+ end
35
+
36
+ it "is accessible" do
37
+ test = TestReadOnly.find(1)
38
+
39
+ test.immutable.should == 'readme'
40
+ end
41
+
42
+ it "cannot be set" do
43
+ test = TestReadOnly.find(1)
44
+
45
+ lambda { test.immutable = 'foo' }.should raise_error(NoMethodError)
46
+ end
47
+
48
+ it "does not respond to setter" do
49
+ test = TestReadOnly.find(1)
50
+
51
+ test.should_not respond_to(:immutable=)
52
+ end
53
+
54
+ it "is excluded when generating json" do
55
+ json = TestReadOnly.find(1).to_json
56
+
57
+ JSON.parse(json).keys.should_not include('immutable')
58
+ end
59
+
60
+ it "is excluded when generating json with child resource" do
61
+ test1 = TestReadOnly.find(1)
62
+ test2 = TestReadOnly.find(1)
63
+ test1.attributes['child'] = test2
64
+
65
+ json = JSON.parse(test1.to_json)
66
+ json.keys.should_not include('immutable')
67
+
68
+ json['child'].keys.should_not include('immutable')
69
+ end
70
+
71
+ it "is excluded when generating json with children collection" do
72
+ test1 = TestReadOnly.find(1)
73
+ test2 = TestReadOnly.find(1)
74
+ test1.attributes['children'] = [test2]
75
+
76
+ json = JSON.parse(test1.to_json)
77
+ json.keys.should_not include('immutable')
78
+
79
+ json['children'].map(&:keys).flatten.should_not include('immutable')
80
+ end
81
+
82
+ it "is excluded xml" do
83
+ xml = TestReadOnly.find(1).to_xml
84
+
85
+ parse_xml(xml).keys.should_not include('immutable')
86
+ end
87
+
88
+ it "is excluded when generating json with child resource" do
89
+ test1 = TestReadOnly.find(1)
90
+ test2 = TestReadOnly.find(1)
91
+ test1.attributes['child'] = test2
92
+
93
+ xml = parse_xml(test1.to_xml)
94
+ xml.keys.should_not include('immutable')
95
+
96
+ xml['child'].keys.should_not include('immutable')
97
+ end
98
+
99
+ it "is excluded when generating json with children collection" do
100
+ test1 = TestReadOnly.find(1)
101
+ test2 = TestReadOnly.find(1)
102
+ test1.attributes['children'] = [test2]
103
+
104
+ xml = parse_xml(test1.to_xml)
105
+ xml.keys.should_not include('immutable')
106
+
107
+ xml['children'].map(&:keys).flatten.should_not include('immutable')
108
+ end
109
+
110
+ it "always loads read_only attributes from the server" do
111
+ test = TestReadOnly.new
112
+ test.read_only.should == []
113
+
114
+ test.save
115
+ test.read_only.should == ['immutable']
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,80 @@
1
+ require 'spec_helper'
2
+
3
+ describe Daylight do
4
+
5
+ class RefinementTestClass < Daylight::API
6
+ self.password = nil
7
+
8
+ scopes :foo, :bar
9
+ end
10
+
11
+ before do
12
+ data = [{name: 'one'}, {name: 'two'}]
13
+ stub_request(:get, %r{#{RefinementTestClass.site}}).to_return(body: data.to_json)
14
+ end
15
+
16
+ describe Daylight::Refinements do
17
+
18
+ it 'allows developers to define which scopes their models support' do
19
+ RefinementTestClass.should respond_to(:foo)
20
+ RefinementTestClass.should respond_to(:bar)
21
+
22
+ RefinementTestClass.scopes :baz
23
+
24
+ RefinementTestClass.should respond_to(:baz)
25
+ end
26
+
27
+ it 'keeps track of scopes' do
28
+ RefinementTestClass.scope_names.should include(:foo)
29
+ RefinementTestClass.scope_names.should include(:bar)
30
+ end
31
+
32
+ it 'allows addition of scopes' do
33
+ names = RefinementTestClass.scope_names
34
+ names.should include(:foo)
35
+ names.should include(:bar)
36
+
37
+ RefinementTestClass.scopes :baz
38
+
39
+ names = RefinementTestClass.scope_names
40
+ names.should include(:foo)
41
+ names.should include(:bar)
42
+ names.should include(:baz)
43
+ end
44
+
45
+ it 'supports first' do
46
+ resource = RefinementTestClass.first
47
+
48
+ resource.should be_kind_of(ActiveResource::Base)
49
+ resource.name.should == 'one'
50
+ end
51
+
52
+ it 'supports first with arguments' do
53
+ resource = RefinementTestClass.first(params: {order: 'name'})
54
+
55
+ resource.should be_kind_of(ActiveResource::Base)
56
+ resource.name.should == 'one'
57
+ end
58
+
59
+ [:where, :find_by, :order, :limit, :offset].each do |method|
60
+ it "delegates '#{method}' to ResourceProxy" do
61
+ RefinementTestClass.should respond_to(method)
62
+ end
63
+ end
64
+
65
+ describe "ResourceProxy class" do
66
+ it "added to subclasses" do
67
+ RefinementTestClass.should be_const_defined(:ResourceProxy)
68
+ end
69
+
70
+ it "accessible from subclass" do
71
+ RefinementTestClass.send(:resource_proxy_class).should == RefinementTestClass::ResourceProxy
72
+ end
73
+
74
+ it "produce a new instance" do
75
+ RefinementTestClass.send(:resource_proxy).class.should == RefinementTestClass::ResourceProxy
76
+ end
77
+ end
78
+
79
+ end
80
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe Daylight::ReflectionExt do
4
+
5
+ module TestAPI
6
+ module V1; end
7
+ end
8
+
9
+ class TestFallback < Daylight::API; end
10
+
11
+ class TestAPI::V1::Comment < Daylight::API; end
12
+
13
+ class TestAPI::V1::Post < Daylight::API
14
+ has_many :comments
15
+ has_many :top_comments, class_name: 'test_api/v1/comment'
16
+
17
+ belongs_to :test_fallback
18
+ end
19
+
20
+ before do
21
+ post_data = {id: 1, title: 'Test Post', test_fallback_id: 3}
22
+ comments_data = [{body: 'comment 1'}, {body: 'comment 2'}]
23
+ fallback_data = {id: 3, name: 'Fallback'}
24
+
25
+ stub_request(:get, %r{#{TestAPI::V1::Post.element_path(1)}}).to_return(body: post_data.to_json)
26
+ stub_request(:get, %r{#{TestAPI::V1::Comment.collection_path}}).to_return(body: comments_data.to_json)
27
+ stub_request(:get, %r{#{TestFallback.element_path(3)}}).to_return(body: fallback_data.to_json)
28
+ end
29
+
30
+ it 'expands class name with namespace and version' do
31
+ comments = TestAPI::V1::Post.find(1).comments
32
+
33
+ comments.size.should == 2
34
+ comments.first.should be_kind_of(TestAPI::V1::Comment)
35
+ end
36
+
37
+
38
+ it 'still overrides classname' do
39
+ comments = TestAPI::V1::Post.find(1).top_comments
40
+
41
+ comments.size.should == 2
42
+ comments.first.should be_kind_of(TestAPI::V1::Comment)
43
+ end
44
+
45
+ it 'falls back to old behavior when class with expanded_name cannot be determined' do
46
+ fallback = TestAPI::V1::Post.find(1).test_fallback
47
+
48
+ fallback.should be_kind_of(TestFallback)
49
+ end
50
+ end