hovercraft 0.0.2 → 0.1.0

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/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -1,5 +1,6 @@
1
1
  require 'hovercraft/loader'
2
- require 'hovercraft/actions'
2
+ require 'hovercraft/routes'
3
+ require 'hovercraft/helpers'
3
4
  require 'sinatra/base'
4
5
  require 'rack/contrib'
5
6
  require 'forwardable'
@@ -22,7 +23,8 @@ module Hovercraft
22
23
  end
23
24
 
24
25
  def configure(application)
25
- application.register(Hovercraft::Actions)
26
+ application.register(Hovercraft::Helpers)
27
+ application.register(Hovercraft::Routes)
26
28
  application.use(Rack::PostBodyContentTypeParser)
27
29
  application
28
30
  end
@@ -0,0 +1,38 @@
1
+ module Hovercraft
2
+ module Helpers
3
+ def self.registered(application)
4
+ application.helpers(Hovercraft::Helpers)
5
+ end
6
+
7
+ def respond_with(content)
8
+ if content.respond_to?(format_method_name)
9
+ content.send(format_method_name)
10
+ else
11
+ fail "Serialization method not supported: #{format_method_name}"
12
+ end
13
+ end
14
+
15
+ def format_method_name
16
+ "to_#{format}"
17
+ end
18
+
19
+ def format
20
+ params[:format] ||
21
+ preferred_type ||
22
+ default_format
23
+ end
24
+
25
+ def preferred_type
26
+ case request.preferred_type
27
+ when /.*\/json/ then :json
28
+ when /.*\/xml/ then :xml
29
+ when /.*\/\*/ then default_format
30
+ else fail "Unknown media type: %p" % request.preferred_type
31
+ end
32
+ end
33
+
34
+ def default_format
35
+ :json
36
+ end
37
+ end
38
+ end
@@ -1,46 +1,44 @@
1
- require 'sinatra/base'
2
-
3
1
  module Hovercraft
4
- module Actions
2
+ module Routes
5
3
  def generate_index(model_class, model_name, plural_model_name)
6
- get("/#{plural_model_name}.:format") do
4
+ get(%r{^/#{plural_model_name}(\.(?<format>[^\./?#]+))?$}) do
7
5
  model_instances = model_class.all
8
6
  status 200
9
- model_instances.to_json
7
+ respond_with model_instances
10
8
  end
11
9
  end
12
10
 
13
11
  def generate_create(model_class, model_name, plural_model_name)
14
- post("/#{plural_model_name}.:format") do
12
+ post(%r{^/#{plural_model_name}(\.(?<format>[^\./?#]+))?$}) do
15
13
  model_instance = model_class.create(params[model_name.to_sym])
16
14
  status model_instance.valid? ? 201 : 400
17
- model_instance.to_json
15
+ respond_with model_instance
18
16
  end
19
17
  end
20
18
 
21
19
  def generate_show(model_class, model_name, plural_model_name)
22
- get("/#{plural_model_name}/:id.:format") do
20
+ get(%r{^/#{plural_model_name}/(?<id>[^\./?#]+)(\.(?<format>[^\./?#]+))?$}) do
23
21
  model_instance = model_class.find(params[:id])
24
22
  status 200
25
- model_instance.to_json
23
+ respond_with model_instance
26
24
  end
27
25
  end
28
26
 
29
27
  def generate_update(model_class, model_name, plural_model_name)
30
- put("/#{plural_model_name}/:id.:format") do
28
+ put(%r{^/#{plural_model_name}/(?<id>[^\./?#]+)(\.(?<format>[^\./?#]+))?$}) do
31
29
  model_instance = model_class.find(params[:id])
32
30
  model_instance.update_attributes(params[model_name.to_sym])
33
31
  status model_instance.valid? ? 204 : 400
34
- model_instance.to_json
32
+ respond_with model_instance
35
33
  end
36
34
  end
37
35
 
38
36
  def generate_destroy(model_class, model_name, plural_model_name)
39
- delete("/#{plural_model_name}/:id.:format") do
37
+ delete(%r{^/#{plural_model_name}/(?<id>[^\./?#]+)(\.(?<format>[^\./?#]+))?$}) do
40
38
  model_instance = model_class.find(params[:id])
41
39
  model_instance.destroy
42
40
  status 204
43
- model_instance.to_json
41
+ respond_with model_instance
44
42
  end
45
43
  end
46
44
  end
@@ -1,3 +1,3 @@
1
1
  module Hovercraft
2
- VERSION = '0.0.2'
2
+ VERSION = '0.1.0'
3
3
  end
@@ -33,8 +33,14 @@ describe Hovercraft::Builder do
33
33
  describe '#configure' do
34
34
  let(:application) { stub(register: nil, use: nil) }
35
35
 
36
+ it 'registers the helper methods' do
37
+ application.should_receive(:register).with(Hovercraft::Helpers)
38
+
39
+ subject.configure(application)
40
+ end
41
+
36
42
  it 'registers the methods to generate actions' do
37
- application.should_receive(:register).with(Hovercraft::Actions)
43
+ application.should_receive(:register).with(Hovercraft::Routes)
38
44
 
39
45
  subject.configure(application)
40
46
  end
@@ -0,0 +1,86 @@
1
+ require 'hovercraft/helpers'
2
+
3
+ describe Hovercraft::Helpers do
4
+ subject { Class.new { extend Hovercraft::Helpers } }
5
+ let(:model_to_json) { stub }
6
+ let(:model) { stub(to_json: model_to_json) }
7
+
8
+ describe '.registered' do
9
+ let(:application) { stub }
10
+
11
+ it 'includes the helpers in the application' do
12
+ application.should_receive(:helpers).with(described_class)
13
+
14
+ Hovercraft::Helpers.registered(application)
15
+ end
16
+ end
17
+
18
+ describe '#respond_with' do
19
+ it 'serializes the content to the preferred format' do
20
+ subject.stub(format: :json)
21
+
22
+ subject.respond_with(model).should == model_to_json
23
+ end
24
+
25
+ it 'fails if the preferred format is not supported' do
26
+ subject.stub(format: :xml)
27
+
28
+ lambda { subject.respond_with(model) }.should raise_error
29
+ end
30
+ end
31
+
32
+ describe '#format' do
33
+ let(:format_param) { stub }
34
+ let(:preferred_type) { stub }
35
+ let(:default_format) { stub }
36
+
37
+ before do
38
+ subject.stub(
39
+ params: { format: nil },
40
+ preferred_type: nil,
41
+ default_format: nil
42
+ )
43
+ end
44
+
45
+ it 'defaults to the format param' do
46
+ subject.stub(params: { format: format_param })
47
+ subject.format.should == format_param
48
+ end
49
+
50
+ it 'falls back on the preferred_type' do
51
+ subject.stub(preferred_type: preferred_type)
52
+ subject.format.should == preferred_type
53
+ end
54
+
55
+ it 'uses the default format as a worst case' do
56
+ subject.stub(default_format: default_format)
57
+ subject.format.should == default_format
58
+ end
59
+ end
60
+
61
+ describe '#preferred_type' do
62
+ let(:default_format) { stub }
63
+
64
+ before { subject.stub(default_format: default_format) }
65
+
66
+ it 'checks for json' do
67
+ subject.stub_chain(:request, :preferred_type) { 'application/json' }
68
+ subject.preferred_type.should == :json
69
+ end
70
+
71
+ it 'checks for xml' do
72
+ subject.stub_chain(:request, :preferred_type) { 'application/xml' }
73
+ subject.preferred_type.should == :xml
74
+ end
75
+
76
+ it 'defaults to json if any format is allowed' do
77
+ subject.stub_chain(:request, :preferred_type) { '*/*' }
78
+ subject.preferred_type.should == default_format
79
+ end
80
+
81
+ it 'fails if the acceptable type is unknown' do
82
+ subject.stub_chain(:request, :preferred_type) { 'unknown/type' }
83
+ lambda { subject.preferred_type.should }.should raise_error
84
+ end
85
+ end
86
+ end
@@ -1,7 +1,9 @@
1
- require 'hovercraft/actions'
1
+ require 'hovercraft/routes'
2
+ require 'hovercraft/helpers'
3
+ require 'sinatra'
2
4
  require 'rack/test'
3
5
 
4
- describe Hovercraft::Actions do
6
+ describe Hovercraft::Routes do
5
7
  include Rack::Test::Methods
6
8
 
7
9
  let(:application) { Sinatra.new }
@@ -50,7 +52,8 @@ describe Hovercraft::Actions do
50
52
  alias :app :application
51
53
 
52
54
  before do
53
- application.register(Hovercraft::Actions)
55
+ application.register(Hovercraft::Helpers)
56
+ application.register(Hovercraft::Routes)
54
57
 
55
58
  model_class.stub(all: models, create: model, find: model)
56
59
  end
@@ -61,7 +64,7 @@ describe Hovercraft::Actions do
61
64
  end
62
65
 
63
66
  it 'generates a GET collection route' do
64
- application.routes['GET'][0][0].should == %r{^/employees(?:\.|%2E)([^/?#]+)$}
67
+ application.routes['GET'][0][0].should == %r{^/employees(\.(?<format>[^\./?#]+))?$}
65
68
  application.routes['GET'][0][1].should == ['format']
66
69
  end
67
70
 
@@ -78,7 +81,7 @@ describe Hovercraft::Actions do
78
81
  end
79
82
 
80
83
  it 'generates a POST collection route' do
81
- application.routes['POST'][0][0].should == %r{^/employees(?:\.|%2E)([^/?#]+)$}
84
+ application.routes['POST'][0][0].should == %r{^/employees(\.(?<format>[^\./?#]+))?$}
82
85
  application.routes['POST'][0][1].should == ['format']
83
86
  end
84
87
 
@@ -103,7 +106,7 @@ describe Hovercraft::Actions do
103
106
  end
104
107
 
105
108
  it 'generates a GET member route' do
106
- application.routes['GET'][0][0].should == %r{^/employees/([^/?#]+)(?:\.|%2E)([^/?#]+)$}
109
+ application.routes['GET'][0][0].should == %r{^/employees/(?<id>[^\./?#]+)(\.(?<format>[^\./?#]+))?$}
107
110
  application.routes['GET'][0][1].should == ['id', 'format']
108
111
  end
109
112
 
@@ -120,7 +123,7 @@ describe Hovercraft::Actions do
120
123
  end
121
124
 
122
125
  it 'generates a PUT member route' do
123
- application.routes['PUT'][0][0].should == %r{^/employees/([^/?#]+)(?:\.|%2E)([^/?#]+)$}
126
+ application.routes['PUT'][0][0].should == %r{^/employees/(?<id>[^\./?#]+)(\.(?<format>[^\./?#]+))?$}
124
127
  application.routes['PUT'][0][1].should == ['id', 'format']
125
128
  end
126
129
 
@@ -145,7 +148,7 @@ describe Hovercraft::Actions do
145
148
  end
146
149
 
147
150
  it 'generates a DELETE member route' do
148
- application.routes['DELETE'][0][0].should == %r{^/employees/([^/?#]+)(?:\.|%2E)([^/?#]+)$}
151
+ application.routes['DELETE'][0][0].should == %r{^/employees/(?<id>[^\./?#]+)(\.(?<format>[^\./?#]+))?$}
149
152
  application.routes['DELETE'][0][1].should == ['id', 'format']
150
153
  end
151
154
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hovercraft
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-11 00:00:00.000000000 Z
12
+ date: 2012-07-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sinatra-activerecord
@@ -115,6 +115,7 @@ extensions: []
115
115
  extra_rdoc_files: []
116
116
  files:
117
117
  - .gitignore
118
+ - .rspec
118
119
  - .travis.yml
119
120
  - Gemfile
120
121
  - LICENSE
@@ -122,16 +123,18 @@ files:
122
123
  - Rakefile
123
124
  - hovercraft.gemspec
124
125
  - lib/hovercraft.rb
125
- - lib/hovercraft/actions.rb
126
126
  - lib/hovercraft/builder.rb
127
127
  - lib/hovercraft/caller.rb
128
+ - lib/hovercraft/helpers.rb
128
129
  - lib/hovercraft/loader.rb
130
+ - lib/hovercraft/routes.rb
129
131
  - lib/hovercraft/server.rb
130
132
  - lib/hovercraft/version.rb
131
- - spec/hovercraft/actions_spec.rb
132
133
  - spec/hovercraft/builder_spec.rb
133
134
  - spec/hovercraft/caller_spec.rb
135
+ - spec/hovercraft/helpers_spec.rb
134
136
  - spec/hovercraft/loader_spec.rb
137
+ - spec/hovercraft/routes_spec.rb
135
138
  - spec/hovercraft/server_spec.rb
136
139
  homepage: ''
137
140
  licenses: []
@@ -147,7 +150,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
147
150
  version: '0'
148
151
  segments:
149
152
  - 0
150
- hash: 1562352661766896187
153
+ hash: -800613418121454242
151
154
  required_rubygems_version: !ruby/object:Gem::Requirement
152
155
  none: false
153
156
  requirements:
@@ -156,7 +159,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
156
159
  version: '0'
157
160
  segments:
158
161
  - 0
159
- hash: 1562352661766896187
162
+ hash: -800613418121454242
160
163
  requirements: []
161
164
  rubyforge_project:
162
165
  rubygems_version: 1.8.23
@@ -167,8 +170,9 @@ summary: There's a lot of boiler plate code that goes into creating an API so wh
167
170
  directory and call the server from the rackup file and you have yourself a perfect
168
171
  API.
169
172
  test_files:
170
- - spec/hovercraft/actions_spec.rb
171
173
  - spec/hovercraft/builder_spec.rb
172
174
  - spec/hovercraft/caller_spec.rb
175
+ - spec/hovercraft/helpers_spec.rb
173
176
  - spec/hovercraft/loader_spec.rb
177
+ - spec/hovercraft/routes_spec.rb
174
178
  - spec/hovercraft/server_spec.rb