cathode 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +346 -125
- data/Rakefile +1 -0
- data/app/controllers/cathode/base_controller.rb +28 -45
- data/app/models/cathode/token.rb +21 -0
- data/config/routes.rb +16 -0
- data/db/migrate/20140425164100_create_cathode_tokens.rb +11 -0
- data/lib/cathode.rb +0 -13
- data/lib/cathode/_version.rb +2 -1
- data/lib/cathode/action.rb +197 -39
- data/lib/cathode/action_dsl.rb +60 -0
- data/lib/cathode/base.rb +81 -12
- data/lib/cathode/create_request.rb +21 -0
- data/lib/cathode/custom_request.rb +5 -0
- data/lib/cathode/debug.rb +25 -0
- data/lib/cathode/destroy_request.rb +13 -0
- data/lib/cathode/engine.rb +9 -0
- data/lib/cathode/exceptions.rb +20 -0
- data/lib/cathode/index_request.rb +40 -0
- data/lib/cathode/object_collection.rb +49 -0
- data/lib/cathode/query.rb +24 -0
- data/lib/cathode/railtie.rb +21 -0
- data/lib/cathode/request.rb +139 -7
- data/lib/cathode/resource.rb +50 -19
- data/lib/cathode/resource_dsl.rb +46 -0
- data/lib/cathode/show_request.rb +13 -0
- data/lib/cathode/update_request.rb +26 -0
- data/lib/cathode/version.rb +112 -23
- data/lib/tasks/cathode_tasks.rake +5 -4
- data/spec/dummy/app/api/api.rb +0 -0
- data/spec/dummy/app/models/payment.rb +3 -0
- data/spec/dummy/app/models/product.rb +1 -0
- data/spec/dummy/app/models/sale.rb +5 -0
- data/spec/dummy/app/models/salesperson.rb +3 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20140409183635_create_sales.rb +11 -0
- data/spec/dummy/db/migrate/20140423172419_create_salespeople.rb +11 -0
- data/spec/dummy/db/migrate/20140424181343_create_payments.rb +10 -0
- data/spec/dummy/db/schema.rb +31 -1
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +1167 -0
- data/spec/dummy/log/test.log +180602 -0
- data/spec/dummy/spec/factories/payments.rb +8 -0
- data/spec/dummy/spec/factories/products.rb +1 -1
- data/spec/dummy/spec/factories/sales.rb +9 -0
- data/spec/dummy/spec/factories/salespeople.rb +7 -0
- data/spec/dummy/spec/requests/requests_spec.rb +434 -0
- data/spec/lib/cathode/action_spec.rb +136 -0
- data/spec/lib/cathode/base_spec.rb +34 -0
- data/spec/lib/cathode/create_request_spec.rb +40 -0
- data/spec/lib/cathode/custom_request_spec.rb +31 -0
- data/spec/lib/cathode/debug_spec.rb +25 -0
- data/spec/lib/cathode/destroy_request_spec.rb +28 -0
- data/spec/lib/cathode/index_request_spec.rb +62 -0
- data/spec/lib/cathode/object_collection_spec.rb +66 -0
- data/spec/lib/cathode/query_spec.rb +28 -0
- data/spec/lib/cathode/request_spec.rb +58 -0
- data/spec/lib/cathode/resource_spec.rb +482 -0
- data/spec/lib/cathode/show_request_spec.rb +23 -0
- data/spec/lib/cathode/update_request_spec.rb +41 -0
- data/spec/lib/cathode/version_spec.rb +416 -0
- data/spec/models/cathode/token_spec.rb +62 -0
- data/spec/spec_helper.rb +8 -2
- data/spec/support/factories/payments.rb +3 -0
- data/spec/support/factories/sale.rb +3 -0
- data/spec/support/factories/salespeople.rb +3 -0
- data/spec/support/factories/token.rb +3 -0
- data/spec/support/helpers.rb +13 -2
- metadata +192 -47
- data/app/helpers/cathode/application_helper.rb +0 -4
- data/spec/dummy/app/api/dummy_api.rb +0 -4
- data/spec/integration/api_spec.rb +0 -88
- data/spec/lib/action_spec.rb +0 -140
- data/spec/lib/base_spec.rb +0 -28
- data/spec/lib/request_spec.rb +0 -5
- data/spec/lib/resources_spec.rb +0 -78
- data/spec/lib/versioning_spec.rb +0 -104
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Cathode::Action do
|
4
|
+
describe '.create' do
|
5
|
+
subject { Cathode::Action.create(action, Cathode::Resource.new(:products), try(:params) || {}, &block) }
|
6
|
+
|
7
|
+
context 'with a default action' do
|
8
|
+
let(:action) { :index }
|
9
|
+
|
10
|
+
context 'with an override' do
|
11
|
+
let(:block) { proc { override { Product.last } } }
|
12
|
+
|
13
|
+
it 'sets the override block' do
|
14
|
+
expect(subject.override_block.call).to eq(Product.last)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'with a replacement' do
|
19
|
+
let(:block) { proc { replace { Product.last } } }
|
20
|
+
|
21
|
+
it 'sets the replacement as the action block' do
|
22
|
+
expect(subject.action_block.call).to eq(Product.last)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'with a custom action' do
|
28
|
+
let(:action) { :custom }
|
29
|
+
let(:block) { proc { Product.last } }
|
30
|
+
|
31
|
+
context 'with method' do
|
32
|
+
let(:params) { { method: :get } }
|
33
|
+
|
34
|
+
it 'creates a CustomAction' do
|
35
|
+
expect(subject.class).to eq(Cathode::CustomAction)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'sets the block as the action block' do
|
39
|
+
expect(subject.action_block.call).to eq(Product.last)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'sets the HTTP method' do
|
43
|
+
expect(subject.http_method).to eq(:get)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'without method' do
|
48
|
+
let(:params) { {} }
|
49
|
+
|
50
|
+
it 'raises an error' do
|
51
|
+
expect { subject }.to raise_error(
|
52
|
+
Cathode::RequestMethodMissingError,
|
53
|
+
"You must specify an HTTP method (get, put, post, delete) for action `custom'"
|
54
|
+
)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'with :index' do
|
60
|
+
let(:action) { :index }
|
61
|
+
let(:block) { nil }
|
62
|
+
|
63
|
+
it 'creates an IndexAction' do
|
64
|
+
expect(subject.class).to eq(Cathode::IndexAction)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'with :show' do
|
69
|
+
let(:action) { :show }
|
70
|
+
let(:block) { nil }
|
71
|
+
|
72
|
+
it 'creates a ShowAction' do
|
73
|
+
expect(subject.class).to eq(Cathode::ShowAction)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'with :create' do
|
78
|
+
let(:action) { :create }
|
79
|
+
|
80
|
+
context 'when attributes specified' do
|
81
|
+
let(:block) do
|
82
|
+
proc { attributes { params.require(:product) } }
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'creates a CreateAction' do
|
86
|
+
expect(subject.after_resource_initialized.class).to eq(Cathode::CreateAction)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'when attributes not specified' do
|
91
|
+
let(:block) { nil }
|
92
|
+
|
93
|
+
it 'raises an error' do
|
94
|
+
expect { subject.after_resource_initialized }.to raise_error(
|
95
|
+
Cathode::UnknownAttributesError,
|
96
|
+
"An attributes block was not specified for `create' action on resource `products'"
|
97
|
+
)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context 'with :update' do
|
103
|
+
let(:action) { :update }
|
104
|
+
|
105
|
+
context 'when attributes specified' do
|
106
|
+
let(:block) do
|
107
|
+
proc { attributes { params.require(:product) } }
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'creates an UpdateAction' do
|
111
|
+
expect(subject.after_resource_initialized.class).to eq(Cathode::UpdateAction)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'when attributes not specified' do
|
116
|
+
let(:block) { nil }
|
117
|
+
|
118
|
+
it 'raises an error' do
|
119
|
+
expect { subject.after_resource_initialized }.to raise_error(
|
120
|
+
Cathode::UnknownAttributesError,
|
121
|
+
"An attributes block was not specified for `update' action on resource `products'"
|
122
|
+
)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
context 'with :destroy' do
|
128
|
+
let(:action) { :destroy }
|
129
|
+
let(:block) { nil }
|
130
|
+
|
131
|
+
it 'creates a DestroyAction' do
|
132
|
+
expect(subject.class).to eq(Cathode::DestroyAction)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Cathode::Base do
|
4
|
+
describe '#version' do
|
5
|
+
subject do
|
6
|
+
Cathode::Base.version 1.5 do
|
7
|
+
resources :products
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'creates a new version' do
|
12
|
+
expect(subject.version).to eq('1.5.0')
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'contains the resources' do
|
16
|
+
expect(subject._resources.names).to eq([:products])
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#define' do
|
21
|
+
context 'with resource name' do
|
22
|
+
subject do
|
23
|
+
Cathode::Base.define do
|
24
|
+
resources :products
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'initializes version 1.0.0' do
|
29
|
+
subject
|
30
|
+
expect(Cathode::Version.find('1.0.0')._resources.find(:products)).to_not be_nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Cathode::CreateRequest do
|
4
|
+
subject do
|
5
|
+
Cathode::CreateRequest.new(context_stub(params: ActionController::Parameters.new(params.merge(controller: 'products', action: 'create'))))
|
6
|
+
end
|
7
|
+
before do
|
8
|
+
use_api do
|
9
|
+
resources :products, actions: [:create] do
|
10
|
+
attributes do
|
11
|
+
params.require(:product).permit(:title)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'with valid attributes' do
|
18
|
+
let(:params) { { product: { title: 'cool product' } } }
|
19
|
+
|
20
|
+
it 'sets status as ok' do
|
21
|
+
expect(subject._status).to eq(:ok)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'sets body as the new record' do
|
25
|
+
expect(subject._body.title).to eq('cool product')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'with invalid attributes' do
|
30
|
+
let(:params) { { title: 'cool product' } }
|
31
|
+
|
32
|
+
it 'sets status as bad request' do
|
33
|
+
expect(subject._status).to eq(:bad_request)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'sets body as error message' do
|
37
|
+
expect(subject._body).to eq('param is missing or the value is empty: product')
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Cathode::CustomRequest do
|
4
|
+
subject do
|
5
|
+
Cathode::CustomRequest.new(context_stub(
|
6
|
+
params: ActionController::Parameters.new(params.merge(controller: 'products', action: 'custom')),
|
7
|
+
path: 'products/custom'
|
8
|
+
))
|
9
|
+
end
|
10
|
+
|
11
|
+
before do
|
12
|
+
use_api do
|
13
|
+
resources :products do
|
14
|
+
get :custom do
|
15
|
+
body Product.last
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
let!(:products) { create_list(:product, 3) }
|
22
|
+
let(:params) { {} }
|
23
|
+
|
24
|
+
it 'sets status as ok' do
|
25
|
+
expect(subject._status).to eq(:ok)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'sets body' do
|
29
|
+
expect(subject._body).to eq(Product.last)
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Cathode::Debug do
|
4
|
+
before do
|
5
|
+
use_api do
|
6
|
+
resources :products, actions: [:index]
|
7
|
+
version 2 do
|
8
|
+
resources :sales, actions: :all do
|
9
|
+
attributes do
|
10
|
+
params.require(:sale)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '.info' do
|
18
|
+
subject { Cathode::Debug.info }
|
19
|
+
|
20
|
+
it 'returns the info' do
|
21
|
+
puts subject
|
22
|
+
# expect(subject).to eq("Version 1.0.0\n\tproducts")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Cathode::DestroyRequest do
|
4
|
+
subject do
|
5
|
+
Cathode::DestroyRequest.new(context_stub(params: ActionController::Parameters.new(params.merge(controller: 'products', action: 'destroy'))))
|
6
|
+
end
|
7
|
+
before do
|
8
|
+
use_api do
|
9
|
+
resources :products, actions: [:destroy]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:action) { 'destroy' }
|
14
|
+
let(:params) { { id: product.id } }
|
15
|
+
let!(:product) { create(:product) }
|
16
|
+
|
17
|
+
it 'sets status as ok' do
|
18
|
+
expect(subject._status).to eq(:ok)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'sets body as empty' do
|
22
|
+
expect(subject._body).to be_empty
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'removes the record' do
|
26
|
+
expect { subject }.to change { Product.count }.by(-1)
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Cathode::IndexRequest do
|
4
|
+
subject do
|
5
|
+
Cathode::IndexRequest.new(context_stub(params: ActionController::Parameters.new(params.merge(controller: resource, action: 'index'))))
|
6
|
+
end
|
7
|
+
let!(:products) { create_list(:product, 5) }
|
8
|
+
before do
|
9
|
+
use_api do
|
10
|
+
resources :products do
|
11
|
+
action :index do
|
12
|
+
allows :paging
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
resources :sales, actions: [:index]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe 'with no params' do
|
21
|
+
let(:params) { {} }
|
22
|
+
let(:resource) { 'products' }
|
23
|
+
let(:block) { nil }
|
24
|
+
|
25
|
+
it 'sets status as ok' do
|
26
|
+
expect(subject._status).to eq(:ok)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'sets body as all resource records' do
|
30
|
+
expect(subject._body).to eq(Product.all)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'with paging' do
|
35
|
+
let(:params) { { page: 2, per_page: 2 } }
|
36
|
+
|
37
|
+
context 'when allowed' do
|
38
|
+
let(:resource) { 'products' }
|
39
|
+
|
40
|
+
it 'sets status as ok' do
|
41
|
+
expect(subject._status).to eq(:ok)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'sets body as the paged results' do
|
45
|
+
expect(subject._body).to eq(products[2..3])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'when not allowed' do
|
50
|
+
let(:resource) { 'sales' }
|
51
|
+
let!(:sales) { create_list(:sale, 5) }
|
52
|
+
|
53
|
+
it 'sets status as ok' do
|
54
|
+
expect(subject._status).to eq(:ok)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'sets body as all records' do
|
58
|
+
expect(subject._body).to eq(sales)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Cathode::ObjectCollection do
|
4
|
+
let(:collection) { Cathode::ObjectCollection.new }
|
5
|
+
let(:obj_struct) { Struct.new(:name) }
|
6
|
+
let(:battery) { obj_struct.new(:battery) }
|
7
|
+
let(:charger) { obj_struct.new(:charger) }
|
8
|
+
before do
|
9
|
+
collection << battery
|
10
|
+
collection << charger
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#find' do
|
14
|
+
subject { collection.find(:battery) }
|
15
|
+
|
16
|
+
it 'returns the item with the matching name' do
|
17
|
+
expect(subject).to eq(battery)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#add' do
|
22
|
+
subject { collection.add(items) }
|
23
|
+
let(:cord) { obj_struct.new(:cord) }
|
24
|
+
let(:connector) { obj_struct.new(:connector) }
|
25
|
+
|
26
|
+
context 'with single item' do
|
27
|
+
let(:items) { cord }
|
28
|
+
|
29
|
+
it 'adds the item to the objects' do
|
30
|
+
expect(subject.objects).to match_array([battery, charger, cord])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'with an array of items' do
|
35
|
+
let(:items) { [cord, connector] }
|
36
|
+
|
37
|
+
it 'adds the items to the objects' do
|
38
|
+
expect(subject.objects).to match_array([battery, charger, cord, connector])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '#delete' do
|
44
|
+
subject { collection.delete(:battery) }
|
45
|
+
|
46
|
+
it 'deletes the object from the collection' do
|
47
|
+
expect(subject.objects).to match_array([charger])
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '#names' do
|
52
|
+
subject { collection.names }
|
53
|
+
|
54
|
+
it 'returns the objects mapped to their names' do
|
55
|
+
expect(subject).to match_array([:battery, :charger])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe 'array methods' do
|
60
|
+
subject { collection.each { |i| i } }
|
61
|
+
|
62
|
+
it 'delegates to the object array' do
|
63
|
+
expect(subject).to match_array([battery, charger])
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Cathode::Query do
|
4
|
+
describe '.new' do
|
5
|
+
subject { Cathode::Query.new(Product, query) }
|
6
|
+
let!(:product1) { create(:product, cost: 500) }
|
7
|
+
let!(:product2) { create(:product, cost: 700) }
|
8
|
+
let!(:product3) { create(:product, cost: 1000) }
|
9
|
+
|
10
|
+
describe 'where' do
|
11
|
+
context 'explicit' do
|
12
|
+
let(:query) { 'where cost > 500' }
|
13
|
+
|
14
|
+
it 'returns the records' do
|
15
|
+
expect(subject.results).to match_array([product2, product3])
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'implicit' do
|
20
|
+
let(:query) { 'cost > 500' }
|
21
|
+
|
22
|
+
it 'returns the records' do
|
23
|
+
expect(subject.results).to match_array([product2, product3])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|