rack-scaffold 0.1.0 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7ef91f24e25308a80570de00566258b1f6dd8ba3
4
- data.tar.gz: 044364fe5fca8ce8bfe21d4ca62f34201b5f2d3b
3
+ metadata.gz: 5d2030b9f5a66a76fcf8f658cf0a83ace7717130
4
+ data.tar.gz: 24a2f01f229584c7482511deb05f38aba9dfe57a
5
5
  SHA512:
6
- metadata.gz: 57c614e8c131c3f8b0aef53b3a2f5b6d4d9ea991ae251e0c4d11623f68a85398920fa5a6e5c139c08dec42bf85dc328a85887305dceb61a9208da601c737e961
7
- data.tar.gz: d2c028e14bd9dd1dc82cc1cdd5be3c216cbbcebef372c9f5c6c1fde50ba2b299bfb08e6ae97fe0db033b6a28722a9e5c311d8a4cb275f9012aafbf8cca6b54ee
6
+ metadata.gz: bc643c54ef2aabd7d762fdcae13e40a32e63bdba17dadf4b725cf1b23a04e599cba2ce95e0948f56d2b7c4249a8cca56eabd6c7caa9e732ab59ea58799078508
7
+ data.tar.gz: d07c15033d0195bdf70381e47c64ecda1fbb818e00aa5d24676014e684b215cb31d7435248c96ac7c05279c5329c490fbf413b48fcfd076dbdc93363d3f399a1
data/Gemfile CHANGED
@@ -1,3 +1,4 @@
1
+ ruby '2.0.0'
1
2
  source "https://rubygems.org"
2
3
 
3
4
  gemspec
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rack-scaffold (0.1.0)
4
+ rack-scaffold (0.2.0)
5
5
  activesupport (>= 3.0)
6
6
  rack (~> 1.4)
7
7
  rack-contrib (~> 1.1)
@@ -12,47 +12,73 @@ PATH
12
12
  GEM
13
13
  remote: https://rubygems.org/
14
14
  specs:
15
- activesupport (4.0.0)
16
- i18n (~> 0.6, >= 0.6.4)
17
- minitest (~> 4.2)
18
- multi_json (~> 1.3)
15
+ activesupport (4.1.5)
16
+ i18n (~> 0.6, >= 0.6.9)
17
+ json (~> 1.7, >= 1.7.7)
18
+ minitest (~> 5.1)
19
19
  thread_safe (~> 0.1)
20
- tzinfo (~> 0.3.37)
21
- atomic (1.1.10)
22
- backports (3.3.3)
23
- eventmachine (1.0.3)
24
- i18n (0.6.4)
25
- minitest (4.7.5)
26
- multi_json (1.7.7)
20
+ tzinfo (~> 1.1)
21
+ backports (3.6.0)
22
+ core_data (0.1.1)
23
+ nokogiri (~> 1.4)
24
+ database_cleaner (1.3.0)
25
+ diff-lcs (1.2.5)
26
+ i18n (0.6.11)
27
+ json (1.8.1)
28
+ mini_portile (0.6.0)
29
+ minitest (5.4.0)
30
+ multi_json (1.10.1)
31
+ nokogiri (1.6.3.1)
32
+ mini_portile (= 0.6.0)
27
33
  rack (1.5.2)
28
34
  rack-contrib (1.1.0)
29
35
  rack (>= 0.9.1)
30
- rack-protection (1.5.0)
36
+ rack-protection (1.5.3)
31
37
  rack
32
38
  rack-test (0.6.2)
33
39
  rack (>= 1.0)
34
- rake (10.0.4)
35
- sinatra (1.4.3)
40
+ rake (10.3.2)
41
+ rspec (3.0.0)
42
+ rspec-core (~> 3.0.0)
43
+ rspec-expectations (~> 3.0.0)
44
+ rspec-mocks (~> 3.0.0)
45
+ rspec-core (3.0.4)
46
+ rspec-support (~> 3.0.0)
47
+ rspec-expectations (3.0.4)
48
+ diff-lcs (>= 1.2.0, < 2.0)
49
+ rspec-support (~> 3.0.0)
50
+ rspec-mocks (3.0.4)
51
+ rspec-support (~> 3.0.0)
52
+ rspec-support (3.0.4)
53
+ sequel (4.13.0)
54
+ sinatra (1.4.5)
36
55
  rack (~> 1.4)
37
56
  rack-protection (~> 1.4)
38
57
  tilt (~> 1.3, >= 1.3.4)
39
- sinatra-contrib (1.4.0)
58
+ sinatra-contrib (1.4.2)
40
59
  backports (>= 2.0)
41
- eventmachine
60
+ multi_json
42
61
  rack-protection
43
62
  rack-test
44
- sinatra (~> 1.4.2)
63
+ sinatra (~> 1.4.0)
45
64
  tilt (~> 1.3)
46
65
  sinatra-param (0.1.3)
47
66
  sinatra (~> 1.3)
48
- thread_safe (0.1.2)
49
- atomic
67
+ sqlite3 (1.3.9)
68
+ thread_safe (0.3.4)
50
69
  tilt (1.4.1)
51
- tzinfo (0.3.37)
70
+ tzinfo (1.2.2)
71
+ thread_safe (~> 0.1)
52
72
 
53
73
  PLATFORMS
54
74
  ruby
55
75
 
56
76
  DEPENDENCIES
77
+ core_data
78
+ database_cleaner
57
79
  rack-scaffold!
80
+ rack-test
58
81
  rake
82
+ rspec
83
+ sequel
84
+ sqlite3
@@ -29,6 +29,9 @@ module Rack
29
29
  end
30
30
 
31
31
  disable :raise_errors, :show_exceptions
32
+ if ENV["RACK_ENV"] == "test"
33
+ set :raise_errors, true
34
+ end
32
35
 
33
36
  def last_modified_time(resource, resources)
34
37
  update_timestamp_field = resource.update_timestamp_field.to_sym
@@ -41,7 +44,7 @@ module Rack
41
44
 
42
45
  def notify!(record)
43
46
  return unless @@connections
44
-
47
+
45
48
  pathname = Pathname.new(request.path)
46
49
 
47
50
  lines = []
@@ -73,7 +76,7 @@ module Rack
73
76
  @@connections = Hash.new([])
74
77
 
75
78
  route :get, :subscribe, "/#{resource.plural}/?" do
76
- pass unless request.accept? 'text/event-stream'
79
+ pass unless request.accept.include? 'text/event-stream'
77
80
 
78
81
  content_type 'text/event-stream'
79
82
 
@@ -89,7 +92,8 @@ module Rack
89
92
 
90
93
  @app.instance_eval do
91
94
  post "/#{resource.plural}/?" do
92
- if record = resource.create!(params)
95
+ record = resource.klass.new(params)
96
+ if record.save
93
97
  status 201
94
98
  notify!(record)
95
99
  {"#{resource.singular}" => record}.to_json
@@ -142,7 +146,7 @@ module Rack
142
146
  "#{association}" => associations
143
147
  }.to_json
144
148
  end
145
- end
149
+ end
146
150
  end if @actions.include?(:read)
147
151
 
148
152
  @app.instance_eval do
@@ -12,19 +12,17 @@ module Rack::Scaffold::Adapters
12
12
 
13
13
  def resources(xcdatamodel, options = {})
14
14
  model = ::CoreData::DataModel.new(xcdatamodel)
15
- resources = model.entities.collect{|entity| resource = new(entity, options)}
16
15
  model.entities.each do |entity|
17
- resources.each do |resource|
18
- resource.establish_associations!(entity)
19
- end
16
+ self.const_set(entity.name.capitalize, Class.new(::Sequel::Model)) unless self.const_defined?(entity.name.capitalize)
20
17
  end
21
18
 
22
- return resources
19
+ model.entities.collect{|entity| new(entity, options)}
23
20
  end
24
21
  end
25
22
 
26
23
  def initialize(entity, options = {})
27
- klass = Class.new(::Sequel::Model)
24
+ adapter = self.class
25
+ klass = adapter.const_get(entity.name.capitalize)
28
26
  klass.dataset = entity.name.downcase.pluralize.to_sym
29
27
 
30
28
  klass.class_eval do
@@ -42,14 +40,31 @@ module Rack::Scaffold::Adapters
42
40
  if options[:timestamps].instance_of? Hash
43
41
  plugin :timestamps, options[:timestamps]
44
42
  else
45
- plugin :timestamps
43
+ plugin :timestamps, update_on_create: true
46
44
  end
47
45
  end
48
46
 
47
+ if options[:nested_attributes]
48
+ plugin :nested_attributes
49
+ end
50
+
49
51
  def url
50
52
  "/#{self.class.table_name}/#{self[primary_key]}"
51
53
  end
52
54
 
55
+ entity.relationships.each do |relationship|
56
+ entity_options = {class: adapter.const_get(relationship.destination.capitalize)}
57
+
58
+ if relationship.to_many?
59
+ one_to_many relationship.name.to_sym, entity_options
60
+ if options[:nested_attributes]
61
+ nested_attributes relationship.name.to_sym
62
+ end
63
+ else
64
+ many_to_one relationship.name.to_sym, options
65
+ end
66
+ end
67
+
53
68
  set_schema do
54
69
  primary_key :id
55
70
 
@@ -57,9 +72,9 @@ module Rack::Scaffold::Adapters
57
72
  next if attribute.transient?
58
73
 
59
74
  options = {
60
- :null => attribute.optional?,
61
- :index => attribute.indexed?,
62
- :default => attribute.default_value
75
+ null: attribute.optional?,
76
+ index: attribute.indexed?,
77
+ default: attribute.default_value
63
78
  }
64
79
 
65
80
  type = case attribute.type
@@ -80,8 +95,8 @@ module Rack::Scaffold::Adapters
80
95
 
81
96
  entity.relationships.each do |relationship|
82
97
  options = {
83
- :index => true,
84
- :null => relationship.optional?
98
+ index: true,
99
+ null: relationship.optional?
85
100
  }
86
101
 
87
102
  if not relationship.to_many?
@@ -116,22 +131,7 @@ module Rack::Scaffold::Adapters
116
131
  end
117
132
  end
118
133
 
119
- super(CoreData.const_set(entity.name, klass))
120
- end
121
-
122
- def establish_associations!(entity)
123
- klass.class_eval do
124
- entity.relationships.each do |relationship|
125
- options = {:class => CoreData.const_get(relationship.destination.capitalize)}
126
-
127
- options = {}
128
- if relationship.to_many?
129
- one_to_many relationship.name.to_sym, options
130
- else
131
- many_to_one relationship.name.to_sym, options
132
- end
133
- end
134
- end
134
+ super(klass)
135
135
  end
136
136
  end
137
137
  end
Binary file
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
7
7
  s.email = "m@mattt.me"
8
8
  s.homepage = "http://mattt.me"
9
9
  s.license = "MIT"
10
- s.version = "0.1.0"
10
+ s.version = "0.2.0"
11
11
  s.platform = Gem::Platform::RUBY
12
12
  s.summary = "Rack::Scaffold"
13
13
  s.description = "Automatically generate RESTful CRUD services"
@@ -20,6 +20,12 @@ Gem::Specification.new do |s|
20
20
  s.add_dependency "activesupport", ">= 3.0"
21
21
 
22
22
  s.add_development_dependency "rake"
23
+ s.add_development_dependency "rspec"
24
+ s.add_development_dependency "sequel"
25
+ s.add_development_dependency "core_data"
26
+ s.add_development_dependency "sqlite3"
27
+ s.add_development_dependency "database_cleaner"
28
+ s.add_development_dependency "rack-test"
23
29
 
24
30
  s.files = Dir["./**/*"].reject { |file| file =~ /\.\/(bin|example|log|pkg|script|spec|test|vendor)/ }
25
31
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
@@ -0,0 +1,150 @@
1
+ require "spec_helper"
2
+
3
+ describe Rack::Scaffold::Adapters::CoreData do
4
+ let(:app) { Rack::Scaffold.new(model: "./example/Example.xcdatamodeld") }
5
+ let(:adapter) { app.instance_variable_get("@adapter") }
6
+
7
+ describe "Artist" do
8
+ describe "collection" do
9
+ subject(:artists) { adapter::Artist.all }
10
+
11
+ it "is empty" do
12
+ is_expected.to be_empty
13
+ end
14
+
15
+ it "has an empty representation" do
16
+ get '/artists'
17
+ expect(last_response.status).to eq(200)
18
+ expect(last_response.body).to eq({artists: []}.to_json)
19
+ end
20
+ end
21
+
22
+ describe "record" do
23
+ let(:attributes) {
24
+ {
25
+ name: "Serge Gainsbourg",
26
+ artistDescription: "Renowned for his often provocative and scandalous releases"
27
+ }
28
+ }
29
+
30
+ before { post '/artists', attributes }
31
+ subject(:artist) { adapter::Artist.first }
32
+
33
+ it do
34
+ expect(last_response.status).to eq(201)
35
+ expect(last_response.body).to eq({artist: artist}.to_json)
36
+ end
37
+
38
+ it "is not nil" do
39
+ is_expected.not_to be_nil
40
+ end
41
+
42
+ it "has attributes in response body" do
43
+ expect(last_response.body).to eq({artist: artist}.to_json)
44
+ end
45
+
46
+ it "has the correct attributes" do
47
+ expect(artist.name).to eq(attributes[:name])
48
+ expect(artist.artistDescription).to eq(attributes[:artistDescription])
49
+ end
50
+
51
+ it "is listed with GET request" do
52
+ get '/artists'
53
+ expect(last_response.body).to eq({artists: [artist]}.to_json)
54
+ end
55
+
56
+ it "is shown with GET request" do
57
+ get '/artists/1'
58
+ expect(last_response.status).to eq(200)
59
+ expect(last_response.body).to eq({artist: artist}.to_json)
60
+ end
61
+
62
+ it "is updated with PUT request" do
63
+ name = "Lucien"
64
+ put '/artists/1', name: name
65
+ expect(last_response.status).to eq(200)
66
+ expect(adapter::Artist.first.name).to eq(name)
67
+ end
68
+
69
+ it "is updated with PATCH request" do
70
+ name = "Lucien"
71
+ patch '/artists/1', name: name
72
+ expect(last_response.status).to eq(200)
73
+ expect(adapter::Artist.first.name).to eq(name)
74
+ end
75
+
76
+ it "is deleted with DELETE request" do
77
+ delete "/artists/#{artist.id}"
78
+ expect(last_response.status).to eq(204)
79
+ expect(adapter::Artist.first(name: artist.name)).to be_nil
80
+ end
81
+ end
82
+ end
83
+
84
+ describe "Song" do
85
+ describe "collection" do
86
+ subject(:songs) { adapter::Song.all }
87
+
88
+ it "is empty" do
89
+ is_expected.to be_empty
90
+ end
91
+
92
+ it "has an empty representation" do
93
+ get '/songs'
94
+ expect(last_response.status).to eq(200)
95
+ expect(last_response.body).to eq({songs: []}.to_json)
96
+ end
97
+ end
98
+
99
+ describe "record" do
100
+ let(:artist) { adapter::Artist.create() }
101
+
102
+ let(:attributes) {
103
+ {
104
+ title: "Black Trombone",
105
+ artist_id: artist.id
106
+ }
107
+ }
108
+
109
+ before { post '/songs', attributes }
110
+ subject(:song) { adapter::Song.first }
111
+
112
+ it do
113
+ expect(last_response.status).to eq(201)
114
+ expect(last_response.body).to eq({song: song}.to_json)
115
+ end
116
+
117
+ it "is listed with GET" do
118
+ get "/artists/#{artist.id}/songs"
119
+ expect(last_response.status).to eq(200)
120
+ expect(last_response.body).to eq({songs: [song]}.to_json)
121
+ end
122
+
123
+ it "is shown with GET request" do
124
+ get "/songs/#{song.id}"
125
+ expect(last_response.status).to eq(200)
126
+ expect(last_response.body).to eq({song: song}.to_json)
127
+ end
128
+
129
+ it "is updated with PUT request" do
130
+ title = "Je T'Aime....Moi Non Plus"
131
+ put "/songs/#{song.id}", title: title
132
+ expect(last_response.status).to eq(200)
133
+ expect(adapter::Song.first.title).to eq(title)
134
+ end
135
+
136
+ it "is updated with PATCH request" do
137
+ title = "Je T'Aime....Moi Non Plus"
138
+ patch "/songs/#{song.id}", title: title
139
+ expect(last_response.status).to eq(200)
140
+ expect(adapter::Song.first.title).to eq(title)
141
+ end
142
+
143
+ it "is deleted with DELETE request" do
144
+ delete "/songs/#{song.id}"
145
+ expect(last_response.status).to eq(204)
146
+ expect(adapter::Song.first(title: song.title)).to be_nil
147
+ end
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,4 @@
1
+ require "spec_helper"
2
+
3
+ describe Rack::Scaffold::Adapters do
4
+ end
@@ -0,0 +1,4 @@
1
+ require "spec_helper"
2
+
3
+ describe Rack::Scaffold do
4
+ end
@@ -0,0 +1,32 @@
1
+ require "rubygems"
2
+ require "bundler/setup"
3
+
4
+ require "rack"
5
+ require "rack/test"
6
+ require "rspec"
7
+
8
+ require "sqlite3"
9
+ require "sequel"
10
+ require "core_data"
11
+ require "rack/scaffold"
12
+
13
+ require "database_cleaner"
14
+
15
+ DB = Sequel.sqlite
16
+
17
+ RSpec.configure do |config|
18
+ config.include Rack::Test::Methods
19
+ config.color = true
20
+
21
+ config.before(:suite) do
22
+ DatabaseCleaner.strategy = :transaction
23
+ end
24
+
25
+ config.before(:each) do
26
+ DatabaseCleaner.start
27
+ end
28
+
29
+ config.after(:each) do
30
+ DatabaseCleaner.clean
31
+ end
32
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-scaffold
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mattt Thompson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-08-28 00:00:00.000000000 Z
11
+ date: 2014-08-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -108,6 +108,90 @@ dependencies:
108
108
  - - '>='
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: sequel
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: core_data
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - '>='
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: sqlite3
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - '>='
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - '>='
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: database_cleaner
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - '>='
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: rack-test
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - '>='
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - '>='
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
111
195
  description: Automatically generate RESTful CRUD services
112
196
  email: m@mattt.me
113
197
  executables: []
@@ -122,9 +206,14 @@ files:
122
206
  - ./lib/rack/scaffold/adapters.rb
123
207
  - ./lib/rack/scaffold.rb
124
208
  - ./LICENSE
209
+ - ./rack-scaffold-0.2.0.gem
125
210
  - ./rack-scaffold.gemspec
126
211
  - ./Rakefile
127
212
  - ./README.md
213
+ - spec/scaffold/adapters/core_data_spec.rb
214
+ - spec/scaffold/adapters_spec.rb
215
+ - spec/scaffold_spec.rb
216
+ - spec/spec_helper.rb
128
217
  homepage: http://mattt.me
129
218
  licenses:
130
219
  - MIT
@@ -145,8 +234,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
145
234
  version: '0'
146
235
  requirements: []
147
236
  rubyforge_project:
148
- rubygems_version: 2.0.3
237
+ rubygems_version: 2.1.11
149
238
  signing_key:
150
239
  specification_version: 4
151
240
  summary: Rack::Scaffold
152
- test_files: []
241
+ test_files:
242
+ - spec/scaffold/adapters/core_data_spec.rb
243
+ - spec/scaffold/adapters_spec.rb
244
+ - spec/scaffold_spec.rb
245
+ - spec/spec_helper.rb