trails-mvc 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.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.gitmodules +0 -0
- data/.rspec +2 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +74 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/server.rb +31 -0
- data/bin/setup +8 -0
- data/bin/trails +4 -0
- data/dynamic-archive/.rspec +2 -0
- data/dynamic-archive/.ruby-version +1 -0
- data/dynamic-archive/Gemfile +6 -0
- data/dynamic-archive/Gemfile.lock +38 -0
- data/dynamic-archive/README.md +40 -0
- data/dynamic-archive/lib/associatable.rb +145 -0
- data/dynamic-archive/lib/base.rb +143 -0
- data/dynamic-archive/lib/db_connection.rb +151 -0
- data/dynamic-archive/lib/searchable.rb +39 -0
- data/dynamic-archive/lib/validatable.rb +71 -0
- data/dynamic-archive/spec/associatable_spec.rb +294 -0
- data/dynamic-archive/spec/base_spec.rb +252 -0
- data/dynamic-archive/spec/searchable_spec.rb +44 -0
- data/dynamic-archive/spec/validatable_spec.rb +81 -0
- data/dynamic-archive/testing_database/database.db +0 -0
- data/dynamic-archive/testing_database/database.rb +6 -0
- data/dynamic-archive/testing_database/migrations/bats_migration.sql +7 -0
- data/dynamic-archive/testing_database/migrations/cats_migration.sql +7 -0
- data/dynamic-archive/testing_database/migrations/houses_migration.sql +4 -0
- data/dynamic-archive/testing_database/migrations/humans_migration.sql +8 -0
- data/dynamic-archive/testing_database/migrations/play_times_migration.sql +8 -0
- data/dynamic-archive/testing_database/migrations/toys_migration.sql +4 -0
- data/dynamic-archive/testing_database/schema.sql +44 -0
- data/dynamic-archive/testing_database/seed.sql +44 -0
- data/lib/asset_server.rb +28 -0
- data/lib/cli.rb +109 -0
- data/lib/controller_base.rb +78 -0
- data/lib/exception_handler.rb +14 -0
- data/lib/flash.rb +24 -0
- data/lib/router.rb +61 -0
- data/lib/session.rb +28 -0
- data/lib/trails.rb +30 -0
- data/lib/version.rb +3 -0
- data/public/assets/application.css +231 -0
- data/public/assets/application.js +9 -0
- data/template/Gemfile +1 -0
- data/template/README.md +0 -0
- data/template/app/controllers/application_controller.rb +2 -0
- data/template/app/controllers/static_controller.rb +4 -0
- data/template/app/views/layouts/application.html.erb +15 -0
- data/template/app/views/static/root.html.erb +73 -0
- data/template/config/database.rb +6 -0
- data/template/config/routes.rb +17 -0
- data/template/db/database.db +0 -0
- data/template/db/database.sql +0 -0
- data/template/db/schema.sql +0 -0
- data/template/db/seed.sql +0 -0
- data/template/public/assets/application.css +1 -0
- data/template/public/assets/application.js +1 -0
- data/trails-mvc.gemspec +42 -0
- metadata +257 -0
@@ -0,0 +1,252 @@
|
|
1
|
+
require 'byebug'
|
2
|
+
require 'base'
|
3
|
+
require 'db_connection'
|
4
|
+
require 'securerandom'
|
5
|
+
|
6
|
+
describe DynamicArchive::Base do
|
7
|
+
before(:each) { DBConnection.reset }
|
8
|
+
after(:each) { DBConnection.reset }
|
9
|
+
|
10
|
+
context 'before ::finalize!' do
|
11
|
+
before(:each) do
|
12
|
+
class Cat < DynamicArchive::Base
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
after(:each) do
|
17
|
+
Object.send(:remove_const, :Cat)
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '::table_name' do
|
21
|
+
it 'generates default name' do
|
22
|
+
expect(Cat.table_name).to eq('cats')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '::table_name=' do
|
27
|
+
it 'sets table name' do
|
28
|
+
class Human < DynamicArchive::Base
|
29
|
+
self.table_name = 'humans'
|
30
|
+
end
|
31
|
+
|
32
|
+
expect(Human.table_name).to eq('humans')
|
33
|
+
|
34
|
+
Object.send(:remove_const, :Human)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '::columns' do
|
39
|
+
it 'returns a list of all column names as symbols' do
|
40
|
+
expect(Cat.columns).to eq([:id, :name, :owner_id])
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'only queries the DB once' do
|
44
|
+
expect(DBConnection).to(
|
45
|
+
receive(:execute2).exactly(1).times.and_call_original)
|
46
|
+
3.times { Cat.columns }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#attributes' do
|
51
|
+
it 'returns @attributes hash byref' do
|
52
|
+
cat_attributes = {name: 'Gizmo'}
|
53
|
+
c = Cat.new
|
54
|
+
c.instance_variable_set('@attributes', cat_attributes)
|
55
|
+
|
56
|
+
expect(c.attributes).to equal(cat_attributes)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'lazily initializes @attributes to an empty hash' do
|
60
|
+
c = Cat.new
|
61
|
+
|
62
|
+
expect(c.instance_variables).not_to include(:@attributes)
|
63
|
+
expect(c.attributes).to eq({})
|
64
|
+
expect(c.instance_variables).to include(:@attributes)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'after ::finalize!' do
|
70
|
+
before(:all) do
|
71
|
+
class Cat < DynamicArchive::Base
|
72
|
+
self.finalize!
|
73
|
+
end
|
74
|
+
|
75
|
+
class Human < DynamicArchive::Base
|
76
|
+
self.table_name = 'humans'
|
77
|
+
|
78
|
+
self.finalize!
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
after(:all) do
|
83
|
+
Object.send(:remove_const, :Cat)
|
84
|
+
Object.send(:remove_const, :Human)
|
85
|
+
end
|
86
|
+
|
87
|
+
describe '::finalize!' do
|
88
|
+
it 'creates getter methods for each column' do
|
89
|
+
c = Cat.new
|
90
|
+
expect(c.respond_to? :something).to be false
|
91
|
+
expect(c.respond_to? :name).to be true
|
92
|
+
expect(c.respond_to? :id).to be true
|
93
|
+
expect(c.respond_to? :owner_id).to be true
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'creates setter methods for each column' do
|
97
|
+
c = Cat.new
|
98
|
+
c.name = "Nick Diaz"
|
99
|
+
c.id = 209
|
100
|
+
c.owner_id = 2
|
101
|
+
expect(c.name).to eq 'Nick Diaz'
|
102
|
+
expect(c.id).to eq 209
|
103
|
+
expect(c.owner_id).to eq 2
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'created getter methods read from attributes hash' do
|
107
|
+
c = Cat.new
|
108
|
+
c.instance_variable_set(:@attributes, {name: "Nick Diaz"})
|
109
|
+
expect(c.name).to eq 'Nick Diaz'
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'created setter methods use attributes hash to store data' do
|
113
|
+
c = Cat.new
|
114
|
+
c.name = "Nick Diaz"
|
115
|
+
|
116
|
+
expect(c.instance_variables).to include(:@attributes)
|
117
|
+
expect(c.instance_variables).not_to include(:@name)
|
118
|
+
expect(c.attributes[:name]).to eq 'Nick Diaz'
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe '#initialize' do
|
123
|
+
it 'calls appropriate setter method for each item in params' do
|
124
|
+
# We have to set method expectations on the cat object *before*
|
125
|
+
# #initialize gets called, so we use ::allocate to create a
|
126
|
+
# blank Cat object first and then call #initialize manually.
|
127
|
+
c = Cat.allocate
|
128
|
+
|
129
|
+
expect(c).to receive(:name=).with('Don Frye')
|
130
|
+
expect(c).to receive(:id=).with(100)
|
131
|
+
expect(c).to receive(:owner_id=).with(4)
|
132
|
+
|
133
|
+
c.send(:initialize, {name: 'Don Frye', id: 100, owner_id: 4})
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'throws an error when given an unknown attribute' do
|
137
|
+
expect do
|
138
|
+
Cat.new(favorite_band: 'Anybody but The Eagles')
|
139
|
+
end.to raise_error "unknown attribute 'favorite_band'"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe '::all, ::parse_all' do
|
144
|
+
it '::all returns all the rows' do
|
145
|
+
cats = Cat.all
|
146
|
+
expect(cats.count).to eq(5)
|
147
|
+
end
|
148
|
+
|
149
|
+
it '::parse_all turns an array of hashes into objects' do
|
150
|
+
hashes = [
|
151
|
+
{ name: 'cat1', owner_id: 1 },
|
152
|
+
{ name: 'cat2', owner_id: 2 }
|
153
|
+
]
|
154
|
+
|
155
|
+
cats = Cat.parse_all(hashes)
|
156
|
+
expect(cats.length).to eq(2)
|
157
|
+
hashes.each_index do |i|
|
158
|
+
expect(cats[i].name).to eq(hashes[i][:name])
|
159
|
+
expect(cats[i].owner_id).to eq(hashes[i][:owner_id])
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
it '::all returns a list of objects, not hashes' do
|
164
|
+
cats = Cat.all
|
165
|
+
cats.each { |cat| expect(cat).to be_instance_of(Cat) }
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
describe '::find' do
|
170
|
+
it 'fetches single objects by id' do
|
171
|
+
c = Cat.find(1)
|
172
|
+
|
173
|
+
expect(c).to be_instance_of(Cat)
|
174
|
+
expect(c.id).to eq(1)
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'returns nil if no object has the given id' do
|
178
|
+
expect(Cat.find(123)).to be_nil
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
describe '#attribute_values' do
|
183
|
+
it 'returns array of values' do
|
184
|
+
cat = Cat.new(id: 123, name: 'cat1', owner_id: 1)
|
185
|
+
|
186
|
+
expect(cat.attribute_values).to eq([123, 'cat1', 1])
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
describe '#insert' do
|
191
|
+
let(:cat) { Cat.new(name: 'Gizmo', owner_id: 1) }
|
192
|
+
|
193
|
+
before(:each) { cat.insert }
|
194
|
+
|
195
|
+
it 'inserts a new record' do
|
196
|
+
expect(Cat.all.count).to eq(6)
|
197
|
+
end
|
198
|
+
|
199
|
+
it 'sets the id once the new record is saved' do
|
200
|
+
expect(cat.id).to eq(DBConnection.last_insert_row_id)
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'creates a new record with the correct values' do
|
204
|
+
# pull the cat again
|
205
|
+
cat2 = Cat.find(cat.id)
|
206
|
+
|
207
|
+
expect(cat2.name).to eq('Gizmo')
|
208
|
+
expect(cat2.owner_id).to eq(1)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
describe '#update' do
|
213
|
+
it 'saves updated attributes to the DB' do
|
214
|
+
human = Human.find(2)
|
215
|
+
|
216
|
+
human.fname = 'Matthew'
|
217
|
+
human.lname = 'von Rubens'
|
218
|
+
human.update
|
219
|
+
|
220
|
+
# pull the human again
|
221
|
+
human = Human.find(2)
|
222
|
+
expect(human.fname).to eq('Matthew')
|
223
|
+
expect(human.lname).to eq('von Rubens')
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
describe '#save' do
|
228
|
+
it 'calls #insert when record does not exist' do
|
229
|
+
human = Human.new
|
230
|
+
expect(human).to receive(:insert)
|
231
|
+
human.save
|
232
|
+
end
|
233
|
+
|
234
|
+
it 'calls #update when record already exists' do
|
235
|
+
human = Human.find(1)
|
236
|
+
expect(human).to receive(:update)
|
237
|
+
human.save
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
describe '#destroy' do
|
242
|
+
it 'deletes the record from the table' do
|
243
|
+
jimmy = Human.new(fname: "Jimmy", lname: "John")
|
244
|
+
jimmy.save
|
245
|
+
expect(jimmy.fname).to eq(Human.all.last.fname)
|
246
|
+
|
247
|
+
jimmy.destroy
|
248
|
+
expect(jimmy.fname).to_not eq(Human.all.last.fname)
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'searchable'
|
2
|
+
|
3
|
+
describe 'Searchable' do
|
4
|
+
before(:each) { DBConnection.reset }
|
5
|
+
after(:each) { DBConnection.reset }
|
6
|
+
|
7
|
+
before(:all) do
|
8
|
+
class Cat < DynamicArchive::Base
|
9
|
+
finalize!
|
10
|
+
end
|
11
|
+
|
12
|
+
class Human < DynamicArchive::Base
|
13
|
+
self.table_name = 'humans'
|
14
|
+
|
15
|
+
finalize!
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it '#where searches with single criterion' do
|
20
|
+
cats = Cat.where(name: 'Breakfast')
|
21
|
+
cat = cats.first
|
22
|
+
|
23
|
+
expect(cats.length).to eq(1)
|
24
|
+
expect(cat.name).to eq('Breakfast')
|
25
|
+
end
|
26
|
+
|
27
|
+
it '#where can return multiple objects' do
|
28
|
+
humans = Human.where(house_id: 1)
|
29
|
+
expect(humans.length).to eq(2)
|
30
|
+
end
|
31
|
+
|
32
|
+
it '#where searches with multiple criteria' do
|
33
|
+
humans = Human.where(fname: 'Matt', house_id: 1)
|
34
|
+
expect(humans.length).to eq(1)
|
35
|
+
|
36
|
+
human = humans[0]
|
37
|
+
expect(human.fname).to eq('Matt')
|
38
|
+
expect(human.house_id).to eq(1)
|
39
|
+
end
|
40
|
+
|
41
|
+
it '#where returns [] if nothing matches the criteria' do
|
42
|
+
expect(Human.where(fname: 'Nowhere', lname: 'Man')).to eq([])
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'validatable'
|
2
|
+
|
3
|
+
describe 'Validatable' do
|
4
|
+
before(:each) { DBConnection.reset }
|
5
|
+
after(:each) { DBConnection.reset }
|
6
|
+
|
7
|
+
before(:all) do
|
8
|
+
class Cat < DynamicArchive::Base
|
9
|
+
finalize!
|
10
|
+
end
|
11
|
+
|
12
|
+
class Human < DynamicArchive::Base
|
13
|
+
self.table_name = 'humans'
|
14
|
+
validates :fname, :lname, presence: true
|
15
|
+
|
16
|
+
finalize!
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it '::validations returns a hash of hashes' do
|
21
|
+
expect(Cat.validations).to be_a(Hash)
|
22
|
+
expect(Cat.validations[:name]).to eq({})
|
23
|
+
end
|
24
|
+
|
25
|
+
it '::validations returns any validations added' do
|
26
|
+
expect(Human.validations[:fname]).to eq({ presence: true })
|
27
|
+
end
|
28
|
+
|
29
|
+
it '#save calls validations' do
|
30
|
+
alex = Human.new(fname: "Alex")
|
31
|
+
expect(Human).to receive(:presence).twice
|
32
|
+
alex.save
|
33
|
+
end
|
34
|
+
|
35
|
+
it "doesn't save invalid instances" do
|
36
|
+
alex = Human.new(fname: "Alex")
|
37
|
+
alex.save
|
38
|
+
expect(alex.errors[0]).to eq("lname did not pass presence validation")
|
39
|
+
expect(Human.all.last.fname).to_not eq("Alex")
|
40
|
+
end
|
41
|
+
|
42
|
+
it "#uniqueness does not prevent updating attributes" do
|
43
|
+
class Human
|
44
|
+
validates :fname, uniqueness: true
|
45
|
+
end
|
46
|
+
|
47
|
+
alex = Human.new(fname: "Alex", lname: "Rodriguez")
|
48
|
+
alex.save
|
49
|
+
alex.lname = "The Great"
|
50
|
+
alex.save
|
51
|
+
|
52
|
+
expect(alex.errors[0]).to be_nil
|
53
|
+
end
|
54
|
+
|
55
|
+
it "#uniqueness doesn't allow two entries with same value if true" do
|
56
|
+
class Human
|
57
|
+
validates :fname, uniqueness: true
|
58
|
+
end
|
59
|
+
|
60
|
+
alex1 = Human.new(fname: "Alex", lname: "Rodriguez")
|
61
|
+
alex1.save
|
62
|
+
|
63
|
+
alex2 = Human.new(fname: "Alex", lname: "de Ronde")
|
64
|
+
alex2.save
|
65
|
+
expect(alex2.errors[0]).to eq("fname did not pass uniqueness validation")
|
66
|
+
end
|
67
|
+
|
68
|
+
it "#uniqueness does not add flag unconstrained attributes" do
|
69
|
+
class Human
|
70
|
+
validates :fname, uniqueness: true
|
71
|
+
end
|
72
|
+
|
73
|
+
alex = Human.new(fname: "Alex", lname: "Rodriguez")
|
74
|
+
alex.save
|
75
|
+
natalie = Human.new(fname: "Natalie", lname: "Lin")
|
76
|
+
natalie.save
|
77
|
+
|
78
|
+
expect(natalie.errors[0]).to be_nil
|
79
|
+
expect(alex.errors[0]).to be_nil
|
80
|
+
end
|
81
|
+
end
|
Binary file
|
@@ -0,0 +1,6 @@
|
|
1
|
+
ENV['ROOT_FOLDER'] = File.dirname(__FILE__)
|
2
|
+
ENV['MIGRATIONS_FOLDER'] = File.join(ENV['ROOT_FOLDER'], 'migrations')
|
3
|
+
|
4
|
+
ENV['SCHEMA_FILE'] = File.join(ENV['ROOT_FOLDER'], 'schema.sql')
|
5
|
+
ENV['SEED_FILE'] = File.join(ENV['ROOT_FOLDER'], 'seed.sql')
|
6
|
+
ENV['DB_FILE'] = File.join(ENV['ROOT_FOLDER'], 'database.db')
|
@@ -0,0 +1,44 @@
|
|
1
|
+
CREATE TABLE bats (
|
2
|
+
id INTEGER PRIMARY KEY,
|
3
|
+
name VARCHAR(255) NOT NULL,
|
4
|
+
owner_id INTEGER,
|
5
|
+
|
6
|
+
FOREIGN KEY(owner_id) REFERENCES human(id)
|
7
|
+
);
|
8
|
+
|
9
|
+
CREATE TABLE cats (
|
10
|
+
id INTEGER PRIMARY KEY,
|
11
|
+
name VARCHAR(255) NOT NULL,
|
12
|
+
owner_id INTEGER,
|
13
|
+
|
14
|
+
FOREIGN KEY(owner_id) REFERENCES human(id)
|
15
|
+
);
|
16
|
+
|
17
|
+
CREATE TABLE houses (
|
18
|
+
id INTEGER PRIMARY KEY,
|
19
|
+
address VARCHAR(255) NOT NULL
|
20
|
+
);
|
21
|
+
|
22
|
+
CREATE TABLE humans (
|
23
|
+
id INTEGER PRIMARY KEY,
|
24
|
+
fname VARCHAR(255) NOT NULL,
|
25
|
+
lname VARCHAR(255) NOT NULL,
|
26
|
+
house_id INTEGER,
|
27
|
+
|
28
|
+
FOREIGN KEY(house_id) REFERENCES human(id)
|
29
|
+
);
|
30
|
+
|
31
|
+
CREATE TABLE play_times (
|
32
|
+
id INTEGER PRIMARY KEY,
|
33
|
+
toy_id INTEGER NOT NULL,
|
34
|
+
cat_id INTEGER NOT NULL,
|
35
|
+
|
36
|
+
FOREIGN KEY(cat_id) REFERENCES cat(id),
|
37
|
+
FOREIGN KEY(toy_id) REFERENCES toy(id)
|
38
|
+
);
|
39
|
+
|
40
|
+
CREATE TABLE toys (
|
41
|
+
id INTEGER PRIMARY KEY,
|
42
|
+
name VARCHAR(255) NOT NULL
|
43
|
+
);
|
44
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
INSERT INTO
|
2
|
+
houses (id, address)
|
3
|
+
VALUES
|
4
|
+
(1, "26th and Guerrero"), (2, "Dolores and Market");
|
5
|
+
|
6
|
+
INSERT INTO
|
7
|
+
humans (id, fname, lname, house_id)
|
8
|
+
VALUES
|
9
|
+
(1, "Devon", "Watts", 1),
|
10
|
+
(2, "Matt", "Rubens", 1),
|
11
|
+
(3, "Ned", "Ruggeri", 2),
|
12
|
+
(4, "Catless", "Human", NULL);
|
13
|
+
|
14
|
+
INSERT INTO
|
15
|
+
cats (id, name, owner_id)
|
16
|
+
VALUES
|
17
|
+
(1, "Breakfast", 1),
|
18
|
+
(2, "Earl", 2),
|
19
|
+
(3, "Haskell", 3),
|
20
|
+
(4, "Markov", 3),
|
21
|
+
(5, "Stray Cat", NULL);
|
22
|
+
|
23
|
+
INSERT INTO
|
24
|
+
toys (id, name)
|
25
|
+
VALUES
|
26
|
+
(1, "fuzzy"),
|
27
|
+
(2, "stringy"),
|
28
|
+
(3, "mouse"),
|
29
|
+
(4, "ball"),
|
30
|
+
(5, "catnip"),
|
31
|
+
(6, "mystery");
|
32
|
+
|
33
|
+
INSERT INTO
|
34
|
+
play_times (id, toy_id, cat_id)
|
35
|
+
VALUES
|
36
|
+
(1, 1, 1),
|
37
|
+
(2, 2, 1),
|
38
|
+
(3, 3, 2),
|
39
|
+
(4, 4, 4),
|
40
|
+
(5, 5, 4),
|
41
|
+
(6, 6, 3),
|
42
|
+
(7, 1, 4),
|
43
|
+
(8, 2, 2),
|
44
|
+
(9, 4, 1);
|
data/lib/asset_server.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
class StaticAssetsServer
|
2
|
+
attr_reader :app, :res, :req
|
3
|
+
|
4
|
+
def initialize(app)
|
5
|
+
@app = app
|
6
|
+
@res = Rack::Response.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
@req = Rack::Request.new(env)
|
11
|
+
if req.path =~ /^\/public\/assets/
|
12
|
+
serve_asset
|
13
|
+
else
|
14
|
+
app.call(env)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def serve_asset
|
20
|
+
asset = File.read(File.join(PROJECT_ROOT, req.path))
|
21
|
+
|
22
|
+
file_type = req.path.match(/\..+$/)[0]
|
23
|
+
res["Content-Type"] = Rack::Mime::MIME_TYPES[file_type]
|
24
|
+
|
25
|
+
res.write(asset)
|
26
|
+
res.finish
|
27
|
+
end
|
28
|
+
end
|
data/lib/cli.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'active_support'
|
3
|
+
require 'active_support/core_ext'
|
4
|
+
require 'active_support/inflector'
|
5
|
+
|
6
|
+
$thor_runner ||= false
|
7
|
+
|
8
|
+
module Trails
|
9
|
+
class Generate < Thor
|
10
|
+
desc "migration <name>", "adds a migration file to 'db/migrations'"
|
11
|
+
def migration(name)
|
12
|
+
file_name = name
|
13
|
+
timestamp = Time.now.to_i
|
14
|
+
|
15
|
+
path = File.join(PROJECT_ROOT, "db/migrations/#{timestamp}_#{file_name}.sql")
|
16
|
+
raise "Migration already created" if File.exist?(path)
|
17
|
+
|
18
|
+
File.new(path, "w")
|
19
|
+
puts "Migration #{file_name} can be found at #{path}"
|
20
|
+
end
|
21
|
+
|
22
|
+
desc "model <name>", "creates a model template file and a migration file"
|
23
|
+
def model(name)
|
24
|
+
model_path = File.join(PROJECT_ROOT, "app/models/#{name.underscore}.rb")
|
25
|
+
raise "Model already created" if File.exist?(model_path)
|
26
|
+
|
27
|
+
File.open(model_path, "w") do |file|
|
28
|
+
file.write("class #{name.camelize} < DynamicArchive::Base\n")
|
29
|
+
file.write(" self.finalize!\n")
|
30
|
+
file.write("end\n")
|
31
|
+
end
|
32
|
+
|
33
|
+
migration(name)
|
34
|
+
puts "Model #{name.camelize} can be found at #{model_path}"
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "controller <name>", "creates a controller file and a view folder"
|
38
|
+
def controller(name)
|
39
|
+
file_name = name.pluralize.underscore
|
40
|
+
controller_name = "#{name.pluralize.camelize}Controller"
|
41
|
+
controller_path = File.join(PROJECT_ROOT, "app/controllers/#{file_name}_controller.rb")
|
42
|
+
view_dir = File.join(PROJECT_ROOT, "app/views/#{file_name}")
|
43
|
+
raise "Controller already created" if File.exist?(controller_path)
|
44
|
+
|
45
|
+
File.open(controller_path, "w") do |file|
|
46
|
+
file.write("class #{controller_name} < ApplicationController\n")
|
47
|
+
file.write("end\n")
|
48
|
+
end
|
49
|
+
Dir.mkdir(view_dir) unless Dir.exist?(view_dir)
|
50
|
+
|
51
|
+
puts "Controller #{controller_name} can be found at #{controller_path}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class DB < Thor
|
56
|
+
desc "reset", "clears the database, runs all migrations, and re-seeds"
|
57
|
+
def reset
|
58
|
+
DBConnection.reset
|
59
|
+
end
|
60
|
+
|
61
|
+
desc "seed", "seeds the database"
|
62
|
+
def seed
|
63
|
+
DBConnection.seed
|
64
|
+
end
|
65
|
+
|
66
|
+
desc "migrate", "runs all pending migrations"
|
67
|
+
def migrate
|
68
|
+
DBConnection.migrate
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class CLI < Thor
|
73
|
+
desc "generate COMMANDS ...ARGS", "generate new model, migration, or controller"
|
74
|
+
subcommand "generate", Generate
|
75
|
+
|
76
|
+
desc "g COMMANDS ...ARGS", "generate new model, migration, or controller"
|
77
|
+
subcommand "g", Generate
|
78
|
+
|
79
|
+
desc "db COMMANDS", "alter the database"
|
80
|
+
subcommand "db", DB
|
81
|
+
|
82
|
+
desc "server", "starts the trails server, default port: 3000"
|
83
|
+
option :port, :default => 3000
|
84
|
+
option :host, :default => "localhost"
|
85
|
+
def server
|
86
|
+
raise "Cannot find Trails App" unless PROJECT_ROOT
|
87
|
+
require_relative "#{PROJECT_ROOT}/config/routes"
|
88
|
+
require_relative '../bin/server'
|
89
|
+
|
90
|
+
server = TrailsServer.new(options[:port], options[:host])
|
91
|
+
server.start
|
92
|
+
end
|
93
|
+
|
94
|
+
desc "s", "starts the trails server, default port: 3000"
|
95
|
+
option :port, :default => 3000
|
96
|
+
option :host, :default => "localhost"
|
97
|
+
alias_method :s, :server
|
98
|
+
|
99
|
+
desc "new NAME", "creates a new Trails application skeleton in '/<name>'"
|
100
|
+
def new(name)
|
101
|
+
app_destination = File.join(Dir.pwd, name)
|
102
|
+
raise "Directory already exists at #{app_destination}" if Dir.exist?(app_destination)
|
103
|
+
|
104
|
+
FileUtils.copy_entry(TEMPLATE_PATH, app_destination)
|
105
|
+
Dir.mkdir(File.join(app_destination, "app/models"))
|
106
|
+
Dir.mkdir(File.join(app_destination, "db/migrations"))
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|