camping 2.1.532 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +72 -53
- data/Rakefile +25 -20
- data/bin/camping +1 -0
- data/book/01_introduction.md +6 -6
- data/book/02_getting_started.md +348 -267
- data/book/03_more_about_controllers.md +124 -0
- data/book/04_more_about_views.md +118 -0
- data/book/05_more_about_markaby.md +173 -0
- data/book/06_more_about_models.md +58 -0
- data/book/06_rules_of_thumb.md +143 -0
- data/book/07_philosophy.md +23 -0
- data/book/08_publishing_an_app.md +118 -0
- data/book/09_upgrade_notes.md +96 -0
- data/book/10_middleware.md +69 -0
- data/book/11_gear.md +50 -0
- data/examples/blog.rb +38 -38
- data/lib/camping/ar.rb +20 -5
- data/lib/camping/commands.rb +388 -0
- data/lib/camping/gear/filters.rb +48 -0
- data/lib/camping/gear/inspection.rb +32 -0
- data/lib/camping/gear/kuddly.rb +178 -0
- data/lib/camping/gear/nancy.rb +170 -0
- data/lib/camping/loads.rb +15 -0
- data/lib/camping/mab.rb +1 -1
- data/lib/camping/reloader.rb +22 -17
- data/lib/camping/server.rb +145 -70
- data/lib/camping/session.rb +8 -5
- data/lib/camping/template.rb +1 -2
- data/lib/camping/tools.rb +43 -0
- data/lib/camping/version.rb +6 -0
- data/lib/camping-unabridged.rb +360 -133
- data/lib/camping.rb +78 -47
- data/lib/campingtrip.md +341 -0
- data/test/app_camping_gear.rb +121 -0
- data/test/app_camping_tools.rb +1 -0
- data/test/app_config.rb +30 -0
- data/test/app_cookies.rb +1 -1
- data/test/app_file.rb +3 -3
- data/test/app_goes_meta.rb +23 -0
- data/test/app_inception.rb +39 -0
- data/test/app_markup.rb +5 -20
- data/test/app_migrations.rb +16 -0
- data/test/app_partials.rb +1 -1
- data/test/app_prefixed.rb +88 -0
- data/test/app_reloader.rb +1 -2
- data/test/app_route_generating.rb +69 -2
- data/test/app_sessions.rb +24 -2
- data/test/app_simple.rb +18 -18
- data/test/apps/migrations.rb +82 -82
- data/test/apps/misc.rb +1 -1
- data/test/gear/gear_nancy.rb +129 -0
- data/test/test_helper.rb +69 -12
- metadata +152 -92
- data/CHANGELOG +0 -145
- data/book/51_upgrading.md +0 -110
@@ -0,0 +1,124 @@
|
|
1
|
+
# Controllers
|
2
|
+
|
3
|
+
What are these _controllers_? This is a good question for a Camping newb. In the [MVC
|
4
|
+
paradigm](http://en.wikipedia.org/wiki/Model%E2%80%93View%E2%80%93Controller#Overview)
|
5
|
+
a Models could be described as a very weird and hard to understand thing.
|
6
|
+
|
7
|
+
When you look in the browser's navigation bar, you will see something like:
|
8
|
+
|
9
|
+
`http://localhost:3301/welcome/to/my/site`
|
10
|
+
|
11
|
+
The Universal Resource Locator (URL) is showing you a "structured" web site
|
12
|
+
running inside a server that listening in the `3301` port. The site's internal
|
13
|
+
routes are "drawing" the path: Inside the `root_dir/` is the directory `/welcome/`
|
14
|
+
and it recursively adds the names of the deeper directories: "to", "my", and "site" (`./to/my/site`).
|
15
|
+
|
16
|
+
But that is virtual, the site doesn't really have a directory structure like that...
|
17
|
+
That would be useless. The site uses a "route drawing system" to get _control_
|
18
|
+
of that route; this is what *the controller* does.
|
19
|
+
|
20
|
+
## Camping Routes and Controllers
|
21
|
+
|
22
|
+
In camping, each _capitalized_ word in a camel-cased contoller declaration is like the
|
23
|
+
words between each slash in a URL. For example:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
WelcomeToMySite
|
27
|
+
```
|
28
|
+
will draw the route:
|
29
|
+
|
30
|
+
```
|
31
|
+
/welcome/to/my/site
|
32
|
+
```
|
33
|
+
|
34
|
+
Or you could instead use the weird R helper to get more specific control of your routes:
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
Welcome < R '/welcome/to/my/site'
|
38
|
+
```
|
39
|
+
|
40
|
+
All of this will be declared inside the Nuts::Controllers module.
|
41
|
+
|
42
|
+
## Controller Parameters
|
43
|
+
|
44
|
+
Controllers can also handle your application's parameters. For example,
|
45
|
+
when the client asks for a route like `/post/1`, a static web server would
|
46
|
+
look out for the directory named "1" and serve the content in that directory.
|
47
|
+
It would need a lot of "number-named" directories to do that simple job.
|
48
|
+
|
49
|
+
But in our case, the controller draws a dynamic path for every asked post. We just need
|
50
|
+
to tell him about the size of the flock.
|
51
|
+
|
52
|
+
In camping, adding `N` or `X` to a controller's declaration tells it to expect a parameter.
|
53
|
+
The `N` suffix, which will match a numbered route, is declared like this:
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
class PostN
|
57
|
+
```
|
58
|
+
|
59
|
+
With this controller, adding a number to the simple `/post` route in your browser will trigger this route. For example,
|
60
|
+
either of these will work:
|
61
|
+
|
62
|
+
```
|
63
|
+
/post/1
|
64
|
+
/post/99
|
65
|
+
```
|
66
|
+
|
67
|
+
But this `N` route will not match against a word. For example, a request for `/pots/mypost`
|
68
|
+
will return 404 (Not Found). Because the `PostN` declaration will only match _Numeric_ parameters.
|
69
|
+
|
70
|
+
If you would like to match something other than a number, you should use the `X` suffix:
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
class PostX
|
74
|
+
```
|
75
|
+
|
76
|
+
The _X_ tells the controller to match anything, including number and words. For example, it will match:
|
77
|
+
|
78
|
+
```
|
79
|
+
/post/1
|
80
|
+
/post/99
|
81
|
+
/post/mypost
|
82
|
+
```
|
83
|
+
|
84
|
+
But it will NOT match: `/post/mypost/1` (or anything that has "/" in the name). Since slashes signify
|
85
|
+
deeper directories, you would need to tell the controller to recognize the deeper directory before using a parameter.
|
86
|
+
You can do this using camel case, followed by the "X" or "N":
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
class PostMypostX
|
90
|
+
```
|
91
|
+
|
92
|
+
## Getting parameters from the controller
|
93
|
+
|
94
|
+
Ok, we have the controller that match parameters; and now what?
|
95
|
+
|
96
|
+
Say that you want to show the post number N requested in the controller. You'll need the
|
97
|
+
number.
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
class PostN
|
101
|
+
def get number
|
102
|
+
p "the parameter was: #{number}"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
```
|
106
|
+
|
107
|
+
Please, do not try that at home. It's very dirty to use a _view_ inside the controller (more on that soon).
|
108
|
+
|
109
|
+
The method `get`, for the `/post/N route`, will take a parameter. That number will by
|
110
|
+
inside the "number parameter". From now, if you want to route something to your
|
111
|
+
post route, you can write a link 100% pragmatically like this:
|
112
|
+
|
113
|
+
```ruby
|
114
|
+
@post=rand 1..9
|
115
|
+
a "See the post number: #{@post}",:href=>R(PostN,@post)
|
116
|
+
```
|
117
|
+
|
118
|
+
For that example, we just choose a random post and then displayed a link to its path.
|
119
|
+
|
120
|
+
> but you told me that I shouldn't write that in the controller...
|
121
|
+
|
122
|
+
Yep...I said that. These things are called "views" because they will
|
123
|
+
be in the user's face. Our client will not see the controllers; they will be hidden from them when they visit our site.
|
124
|
+
Our client will only see the [views](04_more_about_views.md).
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# Views
|
2
|
+
|
3
|
+
The view is the scene for our show. The user is sitting in his chair
|
4
|
+
(the browser) and see on screen actors (the view). Enjoy the show
|
5
|
+
without think that behind the scenes there is a whole team. The team
|
6
|
+
behind the cameras is our controller but the user don't care about
|
7
|
+
that.
|
8
|
+
|
9
|
+
The user only see their browser and our application is just and HTML document.
|
10
|
+
|
11
|
+
|
12
|
+
## Camping Views
|
13
|
+
|
14
|
+
Inside the Nut::Views module, we will write methods. That method shall called
|
15
|
+
with the render sentence. The views do not use class.
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
module Nust::Views
|
19
|
+
|
20
|
+
def post_number
|
21
|
+
p "you asked the post number @postn"
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
```
|
26
|
+
|
27
|
+
Well, well, that was a views, but now: How we show it to the user? We will call
|
28
|
+
the view from the controller. And we pass to the view all the parameters that we
|
29
|
+
want to show.
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
module Nuts::Controller
|
33
|
+
class PostN
|
34
|
+
def get number
|
35
|
+
@postn=number
|
36
|
+
render :post_number
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
```
|
41
|
+
|
42
|
+
We just declared a controller for the route /post/(number here). When the browser
|
43
|
+
ask for the route /post/1 the controller will be trigged and the get
|
44
|
+
method defined inside the class, will respond to the "get" request in
|
45
|
+
the web server.
|
46
|
+
|
47
|
+
The first instruction in our controller, will by write the number in the @postn
|
48
|
+
variable and then "render"
|
49
|
+
|
50
|
+
But what is `render`? This sentence is not from ruby, this is a camping's
|
51
|
+
sentence and mean: -show now the view named (:symbol). It take a symbol
|
52
|
+
as parameter, and the symbol's name, shall be one of these methods
|
53
|
+
declared in the views. Now we have only a view named post_number.
|
54
|
+
|
55
|
+
You could "associate" it MENTALLY as a hash like this:
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
def my_view => render :my_view
|
59
|
+
```
|
60
|
+
|
61
|
+
But that will happen in your mind. In camping these will be happening in
|
62
|
+
the modules, not in a hash, therefore, their are very associated too.
|
63
|
+
|
64
|
+
Imagine your applications as a big building. The controller as the
|
65
|
+
corridors and the views as the offices. Where are the offices and we do
|
66
|
+
in each office?
|
67
|
+
|
68
|
+
## Views and Controllers
|
69
|
+
|
70
|
+
Model View and Controller, are joined but not scrambled. The views use
|
71
|
+
R(ControllerName) for call the controllers and "move". The controller
|
72
|
+
will use "render" for call the view.
|
73
|
+
|
74
|
+
-And now... what do you think we have behind the curtains?
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
module Why::Controllers
|
78
|
+
class CircusCourtains
|
79
|
+
def get
|
80
|
+
require 'endertromb'
|
81
|
+
@monkey=Endertromb::Animals::StartMonkey.new :frog=>true,:place=>:hand
|
82
|
+
render :behind_curtain
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
```
|
87
|
+
|
88
|
+
-OMG! It's a monkey with a start in the hand!
|
89
|
+
|
90
|
+
-yes, ladies and gentleman, we have it just here for you
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
module Views
|
94
|
+
def behind_curtain
|
95
|
+
p @monkey
|
96
|
+
end
|
97
|
+
end
|
98
|
+
```
|
99
|
+
|
100
|
+
No, we don't have it behind the curtains, but the user believe it. There
|
101
|
+
is the view, enjoy the show.
|
102
|
+
|
103
|
+
## Template engine
|
104
|
+
|
105
|
+
We spoke about the views, and HTML, but we are not using html's tags for
|
106
|
+
our view...
|
107
|
+
|
108
|
+
How happening this?
|
109
|
+
|
110
|
+
The rubyist have not necessary to write HTML code. Exists some options
|
111
|
+
named template. That the "p" before the `@monkey` in the view. A template
|
112
|
+
engine is a kind of "pseudo-language" for handle HTML code. In some
|
113
|
+
template engines you will also write HTML in a more easy way. Their also
|
114
|
+
handle ruby data inside HTML. Templates engine are the wheels of the
|
115
|
+
views.
|
116
|
+
|
117
|
+
In camping, you will write views using a template engine named
|
118
|
+
[Markaby](05_more_about_markaby.md) and you will write HTML pragmatically.
|
@@ -0,0 +1,173 @@
|
|
1
|
+
## Where Markaby's come from
|
2
|
+
|
3
|
+
A great musician, writer and programmer (and a bit crazy) named
|
4
|
+
[_why](http://en.wikipedia.org/wiki/Why_the_lucky_stiff) wrote camping. Before
|
5
|
+
banish himself to the dimension from where him come (a place named "the
|
6
|
+
keyhole"); hi also wanted, that the developers, should have not write pure HTML
|
7
|
+
code. Him dream with a world were the programmer write html in their
|
8
|
+
programming language.
|
9
|
+
|
10
|
+
Rails users are very hard guys. Their eat the soup using a fork and generate
|
11
|
+
HTML views in a template engine named Erb. Their use a long set of weird tools
|
12
|
+
for generate that Embedded Ruby (erb), their call it "scaffolding". The basic
|
13
|
+
idea is: "let me rails write html code for you" Many framework have in the
|
14
|
+
README a line that say: "support more populars template engines" but normally
|
15
|
+
peoples uses the default in the framework.
|
16
|
+
|
17
|
+
"Mab" is the template engine used by default in camping. _why Wrote the first
|
18
|
+
implementation named Markaby and then, judofyr and Jenna, power-up markaby
|
19
|
+
writing a more compact version of it.
|
20
|
+
|
21
|
+
While you are writing with mab, will see ruby code front you are eyes, but your
|
22
|
+
mind, will be seen pure HTML without tags. We will be "metaprograming HTML
|
23
|
+
code". In order to show a Header-1 tag, we just call a method named h1 and send
|
24
|
+
the content as parameter. It will make the dirty work writing all the tags just
|
25
|
+
like this:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
h1 'This is a header one'
|
29
|
+
```
|
30
|
+
|
31
|
+
"Write HTML pragmatically" mean: -write html using not html tags.
|
32
|
+
Markaby is a way for write Hyper Text Markup Language (HTML) using Ruby.
|
33
|
+
That do not mean "html knowledge unneeded"
|
34
|
+
|
35
|
+
But that is only the beginning, we can do more wild things.
|
36
|
+
|
37
|
+
## Writing HTML pragmatically
|
38
|
+
|
39
|
+
For example: if we want show a table for show users and their real
|
40
|
+
names:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
# call me using render :users
|
44
|
+
# from a get in the controllers
|
45
|
+
def users
|
46
|
+
table do
|
47
|
+
th 'User'
|
48
|
+
th 'Realname'
|
49
|
+
@users.each do |user,realname|
|
50
|
+
tr do
|
51
|
+
td user
|
52
|
+
td realname
|
53
|
+
end # tr
|
54
|
+
end # each
|
55
|
+
end # table
|
56
|
+
end # def
|
57
|
+
```
|
58
|
+
|
59
|
+
Take a look better [here](https://github.com/camping/mab/blob/master/README.md)
|
60
|
+
|
61
|
+
## Markaby and the layout
|
62
|
+
|
63
|
+
There is a special view named "layout". The layout, is view that will be
|
64
|
+
rendered each time any other view are rendered. In fact, the layout will take
|
65
|
+
the other views for compose himself. The layout is rendered before anything.
|
66
|
+
|
67
|
+
Each time you use the "render" sentence, you will be rendering the
|
68
|
+
layout and the desired view. Because that, wee need some "special"
|
69
|
+
tweaks in the layout. It must have a door with a poster that say:
|
70
|
+
"other view will enter using this door"
|
71
|
+
|
72
|
+
The layout will be rendered, and in some place you will put the other view.
|
73
|
+
This will be done with the "yield" sentence. Put the yield sentence whenever
|
74
|
+
you want rendering all the other views.
|
75
|
+
|
76
|
+
This is very useful, for example: We wan to write a footer in ALL the
|
77
|
+
pages that we are rendering. You can write the footer in every views
|
78
|
+
definition, or just write the footer in the layout.
|
79
|
+
|
80
|
+
Without a layout, if you render the table's views. Camping will drop out the
|
81
|
+
table just like that to the browser's render. It will not draw any body or head
|
82
|
+
tag. Writing body and head in every page could be a very bored task. But do not
|
83
|
+
worry, the layout is here.
|
84
|
+
|
85
|
+
Lets write our layout, with all the HTML shape and including a footer
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
def layout
|
89
|
+
|
90
|
+
html do
|
91
|
+
head do
|
92
|
+
title 'My Blog'
|
93
|
+
end
|
94
|
+
|
95
|
+
body do
|
96
|
+
|
97
|
+
div.wrapper! do
|
98
|
+
self << yield
|
99
|
+
end
|
100
|
+
|
101
|
+
p.footer! do
|
102
|
+
text 'Powered by Camping'
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end # layout
|
108
|
+
```
|
109
|
+
Well, that was wild. Let's see: First we have everything inside a block, the
|
110
|
+
html's block. At the next level, the first block is head, that is rendering
|
111
|
+
something like:
|
112
|
+
|
113
|
+
```html
|
114
|
+
<html>
|
115
|
+
<head>
|
116
|
+
<title> My Blog </title>
|
117
|
+
</head>
|
118
|
+
</html>
|
119
|
+
```
|
120
|
+
|
121
|
+
If you look at the HTML's source of camping, you will see a VERY LOOOONG
|
122
|
+
line with every the HTML code, better do not look it.
|
123
|
+
|
124
|
+
Then, come the more weird thing. A div with a estrange sentence:
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
self << yield
|
128
|
+
```
|
129
|
+
That mean: -put just right here, the other view called.
|
130
|
+
|
131
|
+
In that place, in the center of the div.wrapper, will be placed all our
|
132
|
+
views called using render's sentence.
|
133
|
+
|
134
|
+
When you call:
|
135
|
+
|
136
|
+
```ruby
|
137
|
+
render :someview
|
138
|
+
```
|
139
|
+
|
140
|
+
Camping will rendering before, the layout view, and put all the content
|
141
|
+
of "someview" inside div.wrapper! You shall not write a lot of tag like
|
142
|
+
head or title.
|
143
|
+
|
144
|
+
Finally, it will be rendering a "p" named footer. That will be the footer in
|
145
|
+
all our pages.
|
146
|
+
|
147
|
+
## Tip
|
148
|
+
|
149
|
+
What would happen? If you do this in the layout:
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
head do
|
153
|
+
title "#{@title}"
|
154
|
+
end
|
155
|
+
```
|
156
|
+
|
157
|
+
Hummm... You could "rewrite" the titles of each pages. In the
|
158
|
+
controller, you just need to declare the variable @title, and that will
|
159
|
+
be the title for that page.
|
160
|
+
|
161
|
+
Remember:
|
162
|
+
|
163
|
+
* Views take @variables from the controller
|
164
|
+
* Layout is rendered before any called view.
|
165
|
+
* Markaby is ruby code and it can be embedded
|
166
|
+
* View's modules use not `class` declarations
|
167
|
+
|
168
|
+
In the table example, we used a hash named @users. But. Where come from all
|
169
|
+
thats data?
|
170
|
+
|
171
|
+
It come from the controller, but the controller took it from the
|
172
|
+
[model](06_more_about_models.md). The M of the MVC, the layer who stare
|
173
|
+
the whole bunch of persistent data.
|
@@ -0,0 +1,58 @@
|
|
1
|
+
## More about Models
|
2
|
+
|
3
|
+
Models are used to persist data. That data could be anything. The balance in a bank account, A list of your favorite restaurants, your blog posts, you name it. Camping uses the *ActiveRecord* Gem, an ORM (object-relational mapper), that maps Database tables to objects.
|
4
|
+
|
5
|
+
We define models by inheriting from a base model named Base:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
class User < Base end
|
9
|
+
```
|
10
|
+
|
11
|
+
Very creative. Base is really just an alias for ActiveRecord, nothing fancy. We put our models into a namespaced module named after our App:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
Camping.goes :Nuts
|
15
|
+
|
16
|
+
module Nuts::Models
|
17
|
+
class User < Base end
|
18
|
+
end
|
19
|
+
```
|
20
|
+
|
21
|
+
Remember from earlier that Models need to be defined before our controllers, otherwise we can't use em. So keep them close to the top.
|
22
|
+
|
23
|
+
The new User model we've defined has a small problem, it's completely empty, it doesn't have any data that can be stored in it. Camping models map Database tables to objects automatically, but this model doesn't have a database table yet. To fix that we'll create a migration:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
Camping.goes :Nuts
|
27
|
+
|
28
|
+
module Nuts::Models
|
29
|
+
class User < Base; end
|
30
|
+
|
31
|
+
# Define a migration to add users
|
32
|
+
class AddUser < V 1.2
|
33
|
+
def self.up
|
34
|
+
create_table User.table_name do |t|
|
35
|
+
t.string :username
|
36
|
+
t.string :email
|
37
|
+
t.timestamps
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.down
|
42
|
+
drop_table User.table_name
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
```
|
47
|
+
|
48
|
+
Databases, like birds, migrate. Migrations move our database from one configuration to another. In our case we're adding users. So cool. User's should be able to log in, sign up, maybe make some pages. We could make the next myspace. To get our database to make a users table we need force our app to create the schema.
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
def Nuts.create
|
52
|
+
Nuts::Models.create_schema
|
53
|
+
end
|
54
|
+
```
|
55
|
+
|
56
|
+
Now that puppy will migrate when we launch our app.
|
57
|
+
|
58
|
+
Our Users now have greater hope to survive. So great. I love it.
|
@@ -0,0 +1,143 @@
|
|
1
|
+
# Keep it in one file
|
2
|
+
|
3
|
+
Generally, the idea is keep your app small and store in a single file. Your app will end up with four sections:
|
4
|
+
|
5
|
+
1. Camping setup
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
do
|
9
|
+
require 'rubygems'
|
10
|
+
require 'camping'
|
11
|
+
Camping.goes :Blog
|
12
|
+
end
|
13
|
+
```
|
14
|
+
|
15
|
+
2. Models
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
do
|
19
|
+
module Blog::Models
|
20
|
+
class User < Base; end
|
21
|
+
class Post < Base; belongs_to :user end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
```
|
25
|
+
|
26
|
+
3. Controllers
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
do
|
30
|
+
module Blog::Controllers
|
31
|
+
class Index < R '/'
|
32
|
+
def get; render :index end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
```
|
37
|
+
|
38
|
+
4. Views
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
do
|
42
|
+
module Blog::Views
|
43
|
+
def layout
|
44
|
+
html { body { self << yield } }
|
45
|
+
end
|
46
|
+
def index
|
47
|
+
div.page "Welcome!"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
```
|
52
|
+
|
53
|
+
# What if things get out of hand?
|
54
|
+
|
55
|
+
If you’re piling up models and controllers, your file may begin to exceed 200 lines, which means lots of paging up and down. Go ahead and store your models, controllers and views in three separate files. Your directory structure should end up like this:
|
56
|
+
|
57
|
+
```
|
58
|
+
blog.rb
|
59
|
+
blog/
|
60
|
+
models.rb
|
61
|
+
controllers.rb
|
62
|
+
views.rb
|
63
|
+
```
|
64
|
+
|
65
|
+
(Note, for the development reloading to work, your required files (models.rb etc.) must be in a subdirectory named after your app.)
|
66
|
+
|
67
|
+
Your blog.rb would still contain the setup (No. 1):
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
do
|
71
|
+
require 'rubygems'
|
72
|
+
require 'camping'
|
73
|
+
Camping.goes :Blog
|
74
|
+
require 'blog/helpers' # if needed
|
75
|
+
require 'blog/models'
|
76
|
+
require 'blog/views'
|
77
|
+
require 'blog/controllers'
|
78
|
+
end
|
79
|
+
```
|
80
|
+
|
81
|
+
# Small apps, many mounts
|
82
|
+
|
83
|
+
Rather than building huge Camping apps, the idea here is to write small apps which can each be mounted at directories on your web server. One restriction: these apps will share a database. However, this allows applications to access each other’s tables and simplifies setup and configuration.
|
84
|
+
|
85
|
+
To mount multiple camping apps, you can `require` the app files. When you mount more than one app they won't be mounted according to their parent directory, routing is explicit. If you'd like to give one of your apps a prefix, set the `url_prefix` option in your app:
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
# camp.rb
|
89
|
+
require 'camping'
|
90
|
+
Camping.goes :Blog
|
91
|
+
require 'blog.rb'
|
92
|
+
|
93
|
+
Camping.goes :Wiki
|
94
|
+
require 'wiki.rb'
|
95
|
+
Wiki.set :url_prefix, 'tepee/'
|
96
|
+
|
97
|
+
Camping.goes :Charty
|
98
|
+
require 'charty.rb'
|
99
|
+
Charty.set :url_prefix, 'charts/'
|
100
|
+
|
101
|
+
```
|
102
|
+
|
103
|
+
By default Camping will look for a file called `camp.rb` in the root where Camping is executed. You can also supply a ruby filename to load your apps from there.
|
104
|
+
|
105
|
+
You’ll end up with:
|
106
|
+
```
|
107
|
+
http://localhost:3301/blog, a blogging app.
|
108
|
+
http://localhost:3301/tepee, a wiki app.
|
109
|
+
http://localhost:3301/charts, a charting app.
|
110
|
+
```
|
111
|
+
|
112
|
+
In your app, if you’re using the R() method to build your links, Camping will make sure the mount is added properly to links.
|
113
|
+
|
114
|
+
For example, if R(View, 1) is used in the blogging app mounted at /blog, the link will be written as /blog/view/1. If later you mount the blog at /articles instead, Camping will write the link as /articles/view/1.
|
115
|
+
|
116
|
+
# Give us a create method
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
do
|
120
|
+
def Blog.create
|
121
|
+
# Code in here will run when the app starts, or reloads, but not when requests happen.
|
122
|
+
# You can use it to create database bits and pieces, files, folders, and so on.
|
123
|
+
end
|
124
|
+
end
|
125
|
+
```
|
126
|
+
|
127
|
+
# The camping server
|
128
|
+
|
129
|
+
The Camping Server is basically a set of rules. At the very least, The Camping Server must:
|
130
|
+
|
131
|
+
- Load all Camping apps in a directory.
|
132
|
+
- Load new apps that appear in that directory.
|
133
|
+
- Mount those apps according to their filename. (e.g. blog.rb is mounted at /blog.)
|
134
|
+
- Run each app’s create method upon startup.
|
135
|
+
- Reload the app if its modification time changes.
|
136
|
+
- Reload the app if it requires any files under the same directory and one of their modification times changes.
|
137
|
+
- Support the X-Sendfile header.
|
138
|
+
|
139
|
+
# Bin/camping
|
140
|
+
|
141
|
+
Camping comes with a very simple version of The Camping Server. bin/camping uses either WEBrick or Mongrel (if you have it installed.)
|
142
|
+
|
143
|
+
Run it like this: `camping /var/www/camping/*.` It will follow all of the rules above.
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# Why's origin story
|
2
|
+
|
3
|
+
The philosophy of Camping is a long and winding tail of origin, met by the ideals for the future of many mad hackers. The story of camping begins in 2006 on a cool winters night in Pittsburgh, where we find a hacker hunched over his computer, typing ruby code with his right hand and playing a laser theremin with his left. To the spooky sounds of his own left hand, he hacked through the night. This night, camping was born.
|
4
|
+
|
5
|
+
Lets step back though time for a minute though, to the origins of this man. Once an upstanding PHP developer, he grew weary and tired of his day job, writing endless login pages and checkouts. He dreamt of a world free of his C-flavoured prison. Tales of promised lands, where snake powered ponies run wild, dancing around campfires full of rubies glowing red as blood. They worked him to the bone, until one day his bones just up and left. He couldn't do it any longer! He was on a mission to find that fire which fueled his dreams.
|
6
|
+
|
7
|
+
In seclusion, there isn't much known about this odd man's life. Some say he went crazy. Others say he became a well respected professor. Still others suggest both of these are true. But what we do know, is that it is here, that he developed his love of chunky bacon, foxes, and children shaped like keyholes.
|
8
|
+
|
9
|
+
And so he went on, crafting his mad writings, scribblings of foxes explaining ruby symbols, and making strange music. Soon this man found himself concerned that children had no good way to make their own eBay competitors. For this reason, he created Camping.
|
10
|
+
|
11
|
+
The End.
|
12
|
+
|
13
|
+
# Actual philosophy
|
14
|
+
|
15
|
+
Why The Lucky Stiff is no longer around, so those of us who contributed early on to Camping have since become its caretakers. We continue to push the framework foward, to be more compact, to be faster, easier, more fun. These are our guiding principals:
|
16
|
+
|
17
|
+
- Camping is for everyone. It sure is great to turn an idea in to a single ruby file which creates a website. It's also great to organise an app in to several files sometimes. You can plug bits together all in a row, and grow your evil monkey in to an entire army of evil circus animals!
|
18
|
+
- Camping isn't for making money. You can make money using camping. Nobody will stop you. But we don't have any buzzwords to offer, we won't make your unit tests easier, nor help you do market research. Our main contributors certainly aren't using camping in large scale deployments, and while camping is blazingly fast, we have no idea how well it would work if you ran it on lots of servers!
|
19
|
+
- Camping is really simple. You don't need to know much, to make nifty things with it, and you can really easily add more detailed bits as needed. Your brain will thank you.
|
20
|
+
- Camping apps are easy to automatically reload. Because most of them are just one ruby file.
|
21
|
+
- Camping encourages experimentation. The whole thing is an experiment.
|
22
|
+
- If you're new to ruby, there are heaps of quirky hacks in here which will teach you all sorts of obscure, nifty, and outright strange things about the Ruby language.
|
23
|
+
- Camping doesn't take itself too seriously. We're a fun bunch, living on the edge of zany!
|