camping 2.1.532 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +72 -53
  3. data/Rakefile +25 -20
  4. data/bin/camping +1 -0
  5. data/book/01_introduction.md +6 -6
  6. data/book/02_getting_started.md +348 -267
  7. data/book/03_more_about_controllers.md +124 -0
  8. data/book/04_more_about_views.md +118 -0
  9. data/book/05_more_about_markaby.md +173 -0
  10. data/book/06_more_about_models.md +58 -0
  11. data/book/06_rules_of_thumb.md +143 -0
  12. data/book/07_philosophy.md +23 -0
  13. data/book/08_publishing_an_app.md +118 -0
  14. data/book/09_upgrade_notes.md +96 -0
  15. data/book/10_middleware.md +69 -0
  16. data/book/11_gear.md +50 -0
  17. data/examples/blog.rb +38 -38
  18. data/lib/camping/ar.rb +20 -5
  19. data/lib/camping/commands.rb +388 -0
  20. data/lib/camping/gear/filters.rb +48 -0
  21. data/lib/camping/gear/inspection.rb +32 -0
  22. data/lib/camping/gear/kuddly.rb +178 -0
  23. data/lib/camping/gear/nancy.rb +170 -0
  24. data/lib/camping/loads.rb +15 -0
  25. data/lib/camping/mab.rb +1 -1
  26. data/lib/camping/reloader.rb +22 -17
  27. data/lib/camping/server.rb +145 -70
  28. data/lib/camping/session.rb +8 -5
  29. data/lib/camping/template.rb +1 -2
  30. data/lib/camping/tools.rb +43 -0
  31. data/lib/camping/version.rb +6 -0
  32. data/lib/camping-unabridged.rb +360 -133
  33. data/lib/camping.rb +78 -47
  34. data/lib/campingtrip.md +341 -0
  35. data/test/app_camping_gear.rb +121 -0
  36. data/test/app_camping_tools.rb +1 -0
  37. data/test/app_config.rb +30 -0
  38. data/test/app_cookies.rb +1 -1
  39. data/test/app_file.rb +3 -3
  40. data/test/app_goes_meta.rb +23 -0
  41. data/test/app_inception.rb +39 -0
  42. data/test/app_markup.rb +5 -20
  43. data/test/app_migrations.rb +16 -0
  44. data/test/app_partials.rb +1 -1
  45. data/test/app_prefixed.rb +88 -0
  46. data/test/app_reloader.rb +1 -2
  47. data/test/app_route_generating.rb +69 -2
  48. data/test/app_sessions.rb +24 -2
  49. data/test/app_simple.rb +18 -18
  50. data/test/apps/migrations.rb +82 -82
  51. data/test/apps/misc.rb +1 -1
  52. data/test/gear/gear_nancy.rb +129 -0
  53. data/test/test_helper.rb +69 -12
  54. metadata +152 -92
  55. data/CHANGELOG +0 -145
  56. data/book/51_upgrading.md +0 -110
@@ -0,0 +1,170 @@
1
+ module Gear
2
+
3
+ # Nancy
4
+ #
5
+ # Nancy is Camping gear that adds Sinatra style routing shortcuts to the Object
6
+ # namespace and to camping controllers themselves:
7
+ #
8
+ # get '/' {
9
+ # "Hello World"
10
+ # }
11
+ #
12
+ # Calling the get method creates a controller, and in the event of no default
13
+ # app yet, creates an app named Frank.
14
+ module Nancy
15
+
16
+ class << self
17
+
18
+
19
+ # normalizes the routes provided to the controller, then returns some variables
20
+ # used in make_camping_route
21
+ def normalize_routes(routes)
22
+ s = ""
23
+ rs = ""
24
+ routes.each do |r|
25
+ if r == '/'
26
+ r = 'Index'
27
+ end
28
+ rs += "'#{r}'" + ","
29
+ r.split("/").each(&:capitalize!).each{|t|
30
+ s << t.gsub(/[^a-z0-9A-Z ]/, '')
31
+ }
32
+ # s << r
33
+ end
34
+ rs.chop!
35
+
36
+ symbol = s.to_sym
37
+ {s: s, rs: rs, symbol: symbol}
38
+ end
39
+
40
+ # ensures an app exists for the controllers.
41
+ def ensure_app(app)
42
+ if Camping::Apps.count == 0
43
+ # In the case of a naked sinatra style invokation
44
+ Camping.goes :Frank
45
+ m = Camping::Apps.first
46
+ else
47
+ m = app
48
+ end
49
+ m
50
+ end
51
+
52
+ # Make a camping route provided with a method type, a route, an optional app, and
53
+ # a required block:
54
+ #
55
+ # get '/another/thing' do
56
+ # render :another_view
57
+ # end
58
+ #
59
+ # Calling the shorthand make route helper methods inside of an app module, adds
60
+ # The route to that App. If you don't have any apps yet, then an app named Frank
61
+ # will be made for you.
62
+ def make_camping_route(method, routes, app=nil, &block)
63
+
64
+ inf = caller.first.split(":")
65
+ file_name, line_number = inf[0], inf[1]
66
+
67
+ meth = method.to_s
68
+
69
+ self.normalize_routes(routes) => {s:, rs:, symbol:}
70
+
71
+ m = self.ensure_app app
72
+
73
+ # Controller name
74
+ cname = "#{meth.capitalize}#{symbol.to_s}"
75
+
76
+ begin
77
+ m.module_eval(%Q[
78
+ module Controllers
79
+ class #{cname} < R #{rs}
80
+ end
81
+ end
82
+ ], file_name, line_number.to_i)
83
+ rescue => error
84
+ if error.message.include? "superclass mismatch for class"
85
+ raise "You've probably tried to define the same route twice using the sinatra method. ['#{rs}']"
86
+ else
87
+ raise error
88
+ end
89
+ end
90
+
91
+ # This is an interesting block. At times we'll pass an App to a route
92
+ # which will implicitly call it's `to_proc` method. In those cases, it's
93
+ # that block that is set as the block here, and it returns a Rack response.
94
+ # If we have a rack response instead of string, then we need to extract
95
+ # the response then reassign the values. the r method is a great helper
96
+ # for that.
97
+ constantine = m::X.const_get("#{cname}")
98
+ if block.arity == -1
99
+ constantine.send(:define_method, meth) { |*args|
100
+ block[*args]
101
+ }
102
+ elsif block.arity == 1
103
+ constantine.send(:define_method, meth) {
104
+ res = block[@env] # if we're forwarding a response
105
+ status = res[0]
106
+ headers = res[1]
107
+ body = res[2].flatten.first
108
+ r(status, body, headers)
109
+ }
110
+ else # assuming arity is 0
111
+ constantine.send(:define_method, meth) {
112
+ block[]
113
+ }
114
+ end
115
+
116
+ return nil
117
+ end
118
+
119
+ def included(mod)
120
+ mod.extend(ClassMethods)
121
+ end
122
+
123
+ # required for compliance reasons
124
+ def setup(app, *a, &block) end
125
+
126
+ end
127
+
128
+ module ClassMethods
129
+
130
+ # Helper methods added to your Camping app that facilitates
131
+ def get(*routes, &block) Nancy.make_camping_route('get', routes, self, &block) end
132
+ def put(*routes, &block) Nancy.make_camping_route('put', routes, self, &block) end
133
+ def post(*routes, &block) Nancy.make_camping_route('post', routes, self, &block) end
134
+ def delete(*routes, &block) Nancy.make_camping_route('delete', routes, self, &block) end
135
+ def head(*routes, &block) Nancy.make_camping_route('head', routes, self, &block) end
136
+ def patch(*routes, &block) Nancy.make_camping_route('patch', routes, self, &block) end
137
+ def link(*routes, &block) Nancy.make_camping_route('link', routes, self, &block) end
138
+ def unlink(*routes, &block) Nancy.make_camping_route('unlink', routes, self, &block) end
139
+
140
+ # Turns this App into a proc to be consumed by one of the block based route generators
141
+ # An easy way to forward requests to an app.
142
+ # a references self, that's then captured by the proc, which is a closure.
143
+ # because it's a closure, and because it captures self, we can then call
144
+ # this proc anywhere we want.
145
+ #
146
+ # The syntax: `a[e]` is an implicit call to the `#call` method. the brackets
147
+ # are syntatic sugar to get this to work. The following code is equivalent:
148
+ #
149
+ # e = [] # given e is a rack array.
150
+ # a.call(e)
151
+ # a.(e)
152
+ # a[e]
153
+ #
154
+ # This code is defined in the Nancy Camping Gear. Specifically in it's
155
+ # ClassMethods module. ClassMethods is then extended onto our Camping app,
156
+ # Giving it the appearance of being a method of the module. In our cases
157
+ # Our modules are our Apps.
158
+ # The code:
159
+ #
160
+ # def to_proc = method(:call).to_proc
161
+ #
162
+ # First gets a `Method` object from the app, then converts it to a proc.
163
+ # In our case we just want call, so this makes the whole api pretty simple.
164
+ # def to_proc = method(:call).to_proc
165
+ def to_proc = method(:call).to_proc
166
+
167
+ end
168
+
169
+ end
170
+ end
@@ -0,0 +1,15 @@
1
+ # Loads things into camping.rb
2
+
3
+ # external dependencies
4
+ require "uri"
5
+ require "rack"
6
+ require 'rubygems'
7
+ require 'bundler/setup'
8
+
9
+ # internal dependencies
10
+ require 'camping/tools'
11
+ require 'camping/gear/filters'
12
+ require 'camping/gear/nancy'
13
+ require 'camping/gear/inspection'
14
+ require 'camping/gear/kuddly'
15
+
data/lib/camping/mab.rb CHANGED
@@ -33,7 +33,7 @@ $MAB_CODE = %q{
33
33
  end
34
34
  }
35
35
 
36
- Camping::S.sub! /autoload\s*:Mab\s*,\s*['"]camping\/mab['"]/, $MAB_CODE
36
+ Camping::S.sub!(/autoload\s*:Mab\s*,\s*['"]camping\/mab['"]/, $MAB_CODE)
37
37
  Camping::Apps.each do |c|
38
38
  c.module_eval $MAB_CODE
39
39
  end
@@ -33,13 +33,14 @@ module Camping
33
33
  # You can also give Reloader more than one script.
34
34
  class Reloader
35
35
  attr_reader :file
36
-
36
+
37
37
  def initialize(file, &blk)
38
38
  @file = file
39
39
  @mtime = Time.at(0)
40
40
  @requires = []
41
41
  @apps = {}
42
42
  @callback = blk
43
+
43
44
  end
44
45
 
45
46
  def name
@@ -50,8 +51,8 @@ module Camping
50
51
  File.basename(base).to_sym
51
52
  end
52
53
  end
53
-
54
- # Loads the apps availble in this script. Use <tt>apps</tt> to get
54
+
55
+ # Loads the apps available in this script. Use <tt>apps</tt> to get
55
56
  # the loaded apps.
56
57
  def load_apps(old_apps)
57
58
  all_requires = $LOADED_FEATURES.dup
@@ -62,7 +63,7 @@ module Camping
62
63
  @requires = []
63
64
  dirs = []
64
65
  new_apps = Camping::Apps - all_apps
65
-
66
+
66
67
  @apps = new_apps.inject({}) do |hash, app|
67
68
  if file = app.options[:__FILE__]
68
69
  full = File.expand_path(file)
@@ -72,7 +73,7 @@ module Camping
72
73
 
73
74
  key = app.name.to_sym
74
75
  hash[key] = app
75
-
76
+
76
77
  if !old_apps.include?(key)
77
78
  @callback.call(app) if @callback
78
79
  app.create if app.respond_to?(:create)
@@ -87,18 +88,22 @@ module Camping
87
88
  end
88
89
 
89
90
  @mtime = mtime
90
-
91
+
91
92
  self
92
93
  end
93
94
 
95
+ # load_file
96
+ #
97
+ # Rack::Builder is mainly used to parse a config.ru file and to
98
+ # build a rack app with middleware from that.
94
99
  def load_file
95
100
  if @file =~ /\.ru$/
96
- @app,_ = Rack::Builder.parse_file(@file)
101
+ @app = Rack::Builder.parse_file(@file)
97
102
  else
98
103
  load(@file)
99
104
  end
100
105
  end
101
-
106
+
102
107
  # Removes all the apps defined in this script.
103
108
  def remove_apps
104
109
  @requires.each do |(path, full)|
@@ -112,7 +117,7 @@ module Camping
112
117
  ensure
113
118
  @apps.clear
114
119
  end
115
-
120
+
116
121
  # Reloads the file if needed. No harm is done by calling this multiple
117
122
  # times, so feel free call just to be sure.
118
123
  def reload
@@ -123,7 +128,7 @@ module Camping
123
128
  def reload!
124
129
  load_apps(remove_apps)
125
130
  end
126
-
131
+
127
132
  # Checks if both scripts watches the same file.
128
133
  def ==(other)
129
134
  @file == other.file
@@ -136,20 +141,20 @@ module Camping
136
141
  @apps
137
142
  end
138
143
  end
139
-
144
+
140
145
  private
141
-
146
+
142
147
  def mtime
143
148
  @requires.map do |(path, full)|
144
149
  File.mtime(full)
145
150
  end.reject {|t| t > Time.now }.max || Time.now
146
151
  end
147
-
148
- # Figures out the full path of a required file.
152
+
153
+ # Figures out the full path of a required file.
149
154
  def full_path(req)
150
- return req if File.exists?(req)
151
- dir = $LOAD_PATH.detect { |l| File.exists?(File.join(l, req)) }
152
- if dir
155
+ return req if File.exist?(req)
156
+ dir = $LOAD_PATH.detect { |l| File.exist?(File.join(l, req)) }
157
+ if dir
153
158
  File.expand_path(req, File.expand_path(dir))
154
159
  else
155
160
  req
@@ -1,15 +1,17 @@
1
1
  require 'irb'
2
2
  require 'erb'
3
3
  require 'rack'
4
+ require 'rackup'
5
+ require 'camping/version'
4
6
  require 'camping/reloader'
7
+ require 'camping/commands'
5
8
 
6
9
  # == The Camping Server (for development)
7
10
  #
8
11
  # Camping includes a pretty nifty server which is built for development.
9
12
  # It follows these rules:
10
- #
11
- # * Load all Camping apps in a directory or a file.
12
- # * Load new apps that appear in that directory or that file.
13
+ #
14
+ # * Load all Camping apps in a file.
13
15
  # * Mount those apps according to their name. (e.g. Blog is mounted at /blog.)
14
16
  # * Run each app's <tt>create</tt> method upon startup.
15
17
  # * Reload the app if its modification time changes.
@@ -19,109 +21,88 @@ require 'camping/reloader'
19
21
  #
20
22
  # Run it like this:
21
23
  #
22
- # camping examples/ # Mounts all apps in that directory
23
24
  # camping blog.rb # Mounts Blog at /
24
25
  #
25
26
  # And visit http://localhost:3301/ in your browser.
26
27
  module Camping
27
- class Server < Rack::Server
28
+ class Server < Rackup::Server
28
29
  class Options
29
- if home = ENV['HOME'] # POSIX
30
- DB = File.join(home, '.camping.db')
31
- RC = File.join(home, '.campingrc')
32
- elsif home = ENV['APPDATA'] # MSWIN
33
- DB = File.join(home, 'Camping.db')
34
- RC = File.join(home, 'Campingrc')
35
- else
36
- DB = nil
37
- RC = nil
38
- end
39
-
40
- HOME = File.expand_path(home) + '/'
41
-
30
+
42
31
  def parse!(args)
43
32
  args = args.dup
44
33
  options = {}
45
-
46
34
  opt_parser = OptionParser.new("", 24, ' ') do |opts|
47
- opts.banner = "Usage: camping my-camping-app.rb"
48
- opts.define_head "#{File.basename($0)}, the microframework ON-button for ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
35
+ opts.banner = "Usage: camping Or: camping my-camping-app.rb"
36
+
37
+ # opts.define_head "#{File.basename($0)}, the microframework ON-button for ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
38
+
49
39
  opts.separator ""
50
40
  opts.separator "Specific options:"
51
-
41
+
52
42
  opts.on("-h", "--host HOSTNAME",
53
43
  "Host for web server to bind to (default is all IPs)") { |v| options[:Host] = v }
54
-
44
+
55
45
  opts.on("-p", "--port NUM",
56
46
  "Port for web server (defaults to 3301)") { |v| options[:Port] = v }
57
-
58
- db = DB.sub(HOME, '~/') if DB
59
- opts.on("-d", "--database FILE",
60
- "SQLite3 database path (defaults to #{db ? db : '<none>'})") { |db_path| options[:database] = db_path }
61
-
62
- opts.on("-C", "--console",
47
+
48
+ opts.on("-c", "--console",
63
49
  "Run in console mode with IRB") { options[:server] = "console" }
64
-
65
- server_list = ["thin", "webrick", "console"]
50
+
51
+ opts.on("-e", "--env ENVIRONMENT",
52
+ "Sets the environment. (defaults: development)") { |v| options[:environment] = ENV['environment'] = v }
53
+
54
+ server_list = ["thin", "webrick", "console", "puma", "tipi", "falcon"]
66
55
  opts.on("-s", "--server NAME",
67
56
  "Server to force (#{server_list.join(', ')})") { |v| options[:server] = v }
68
57
 
69
58
  opts.separator ""
70
59
  opts.separator "Common options:"
71
-
60
+
72
61
  # No argument, shows at tail. This will print an options summary.
73
62
  # Try it and see!
74
- opts.on_tail("-?", "--help", "Show this message") do
63
+ opts.on("-?", "--help", "Show this message") do
75
64
  puts opts
76
65
  exit
77
66
  end
78
67
 
79
68
  # Another typical switch to print the version.
80
- opts.on_tail("-v", "--version", "Show version") do
81
- puts Gem.loaded_specs['camping'].version
82
- exit
83
- end
69
+ opts.on("-v", "--version", "Show version") { options[:version] = true }
70
+
71
+ # Show Routes
72
+ opts.on("-r", "--routes", "Show Routes") { options[:routes] = true }
73
+
84
74
  end
85
-
75
+
86
76
  opt_parser.parse!(args)
87
-
77
+
88
78
  if args.empty?
89
- puts opt_parser
90
- exit
79
+ args << "camp.rb"
91
80
  end
92
-
81
+
93
82
  options[:script] = args.shift
94
83
  options
95
84
  end
96
85
  end
97
-
86
+
98
87
  def initialize(*)
99
88
  super
100
89
  @reloader = Camping::Reloader.new(options[:script]) do |app|
101
90
  if !app.options.has_key?(:dynamic_templates)
102
91
  app.options[:dynamic_templates] = true
103
92
  end
104
-
105
- if !Camping::Models.autoload?(:Base) && options[:database]
106
- Camping::Models::Base.establish_connection(
107
- :adapter => 'sqlite3',
108
- :database => options[:database]
109
- )
110
- end
111
93
  end
112
94
  end
113
-
95
+
114
96
  def opt_parser
115
97
  Options.new
116
98
  end
117
99
 
118
100
  def default_options
119
101
  super.merge({
120
- :Port => 3301,
121
- :database => Options::DB
102
+ :Port => 3301
122
103
  })
123
104
  end
124
-
105
+
125
106
  def middleware
126
107
  h = super
127
108
  h["development"] << [XSendfile]
@@ -129,6 +110,33 @@ module Camping
129
110
  end
130
111
 
131
112
  def start
113
+
114
+ commands = []
115
+ ARGV.each do |cmd|
116
+ commands << cmd
117
+ end
118
+
119
+ # Parse commands
120
+ case commands[0]
121
+ when "new"
122
+ Camping::Commands.new_cmd(commands[1])
123
+ exit
124
+ end
125
+
126
+ if options[:version] == true
127
+ puts "Camping v#{Camping::VERSION}"
128
+ exit
129
+ end
130
+
131
+ if options[:routes] == true
132
+ @reloader.reload!
133
+ r = @reloader
134
+ eval("self", TOPLEVEL_BINDING).meta_def(:reload!) { r.reload!; nil }
135
+ ARGV.clear
136
+ Camping::Commands.routes
137
+ exit
138
+ end
139
+
132
140
  if options[:server] == "console"
133
141
  puts "** Starting console"
134
142
  @reloader.reload!
@@ -138,52 +146,119 @@ module Camping
138
146
  IRB.start
139
147
  exit
140
148
  else
149
+ @reloader.reload!
150
+ r = @reloader
151
+ Camping.make_camp
141
152
  name = server.name[/\w+$/]
142
153
  puts "** Starting #{name} on #{options[:Host]}:#{options[:Port]}"
143
154
  super
144
155
  end
145
156
  end
146
157
 
158
+ # defines the public directory to be /public
147
159
  def public_dir
148
160
  File.expand_path('../public', @reloader.file)
149
161
  end
150
-
162
+
163
+ # add the public directory as a Rack app serving files first, then the
164
+ # current value of self, which is our camping apps, as an app.
151
165
  def app
152
- Rack::Cascade.new([Rack::File.new(public_dir), self], [405, 404, 403])
166
+ Rack::Cascade.new([Rack::Files.new(public_dir), self], [405, 404, 403])
153
167
  end
154
-
155
- def current_app
156
- @reloader.reload
157
- apps = @reloader.apps
158
- return apps.values.first if apps.size == 1
159
- if key = apps.keys.grep(/^#{@reloader.name}$/i)[0]
160
- apps[key]
168
+
169
+ # path_matches?
170
+ # accepts a regular expression string
171
+ # in our case our apps and controllers
172
+ def path_matches?(path, *reg)
173
+ p = T.(path)
174
+ reg.each do |r|
175
+ return true if Regexp.new(T.(r)).match?(p) && p == T.(r)
161
176
  end
177
+ false
162
178
  end
163
179
 
180
+ # Ensure trailing slash lambda
181
+ T ||= -> (u) {
182
+ u << "/" if u[-1] != "/"; u
183
+ }
184
+
185
+ # call(env) res
186
+ # == How routing works
187
+ #
188
+ # The first app added using Camping.goes is set at the root, we walk through
189
+ # the defined routes of the first app to see if there is a match.
190
+ # With no match we then walk through every other defined app.
191
+ # When we reach a matching route we call that app and Camping's router
192
+ # handles the rest.
193
+ #
194
+ # Mounting apps at different directories is now explicit by setting the
195
+ # url_prefix option:
196
+ #
197
+ # camping.goes :Nuts # Mounts Nuts at /
198
+ # module Auth
199
+ # set :url_prefix, "auth/"
200
+ # end
201
+ # camping.goes :Auth # Mounts Auth at /auth/
202
+ # camping.goes :Blog # Mounts Blog at /
203
+ #
204
+ # Note that routes that you set explicitly with R are not prefixed. This
205
+ # us explicit control over routes:
206
+ #
207
+ # module Auth::Controllers
208
+ # class Whatever < R '/thing/' # Mounts at /thing/
209
+ # def get
210
+ # render :some_view
211
+ # end
212
+ # end
213
+ # end
214
+ #
164
215
  def call(env)
165
- app = current_app || raise("Could not find an app called `#{@reloader.name}`")
166
- app.call(env)
216
+ if ENV['environment'] == 'development'
217
+ @reloader.reload
218
+ Camping.make_camp
219
+ end
220
+
221
+ # our switch statement iterates through possible app outcomes, no apps
222
+ # loaded, one app loaded, or multiple apps loaded.
223
+ case @reloader.apps.length
224
+ when 0
225
+ [200, {'content-type' => 'text/html'}, ["I'm sorry but no apps were found."]]
226
+ when 1
227
+ @reloader.apps.values.first.call(env) # When we have one
228
+ else
229
+ # 2 and up get special treatment
230
+ @reloader.apps.each do |name, app|
231
+ app.routes.each do |r|
232
+ if (path_matches?(env['PATH_INFO'], r))
233
+ return app.call(env)
234
+ next
235
+ end
236
+ end
237
+ end
238
+
239
+ # Just return the first app if we didn't find a match.
240
+ @reloader.apps.values.first.call(env)
241
+ end
167
242
  end
168
-
243
+
169
244
  class XSendfile
170
245
  def initialize(app)
171
246
  @app = app
172
247
  end
173
-
248
+
174
249
  def call(env)
175
250
  status, headers, body = @app.call(env)
176
-
251
+
177
252
  if key = headers.keys.grep(/X-Sendfile/i).first
178
253
  filename = headers[key]
179
254
  content = open(filename,'rb') { | io | io.read}
180
255
  headers['Content-Length'] = size(content).to_s
181
256
  body = [content]
182
257
  end
183
-
258
+
184
259
  return status, headers, body
185
260
  end
186
-
261
+
187
262
  if "".respond_to?(:bytesize)
188
263
  def size(str)
189
264
  str.bytesize
@@ -1,3 +1,6 @@
1
+ require 'rack/session'
2
+ class InsecureSecret < Exception #:nodoc: all
3
+ end
1
4
  module Camping
2
5
  # == Getting Started
3
6
  #
@@ -9,7 +12,7 @@ module Camping
9
12
  # to store your application's data.
10
13
  #
11
14
  # require 'camping/session' # 1
12
- #
15
+ #
13
16
  # module Nuts
14
17
  # set :secret, "Oh yeah!" # 2
15
18
  # include Camping::Session # 3
@@ -27,9 +30,9 @@ module Camping
27
30
  module Session
28
31
  def self.included(app)
29
32
  key = "#{app}.state".downcase
30
- secret = app.options[:secret] || [__FILE__, File.mtime(__FILE__)].join(":")
31
-
32
- app.use Rack::Session::Cookie, :key => key, :secret => secret
33
+ secret = app.options[:secret] || ['camping-secret',__FILE__, File.mtime('Rakefile')].join(":")*2
34
+ raise InsecureSecret, "You're Session Secret is too short. Minimum length is 64." if secret.length < 64
35
+ app.use Rack::Session::Cookie, :key => key, :secrets => secret
33
36
  end
34
37
  end
35
- end
38
+ end
@@ -8,10 +8,9 @@ end
8
8
 
9
9
  $TILT_CODE = %{
10
10
  Template = Tilt
11
- include Tilt::CompileSite unless self.options[:dynamic_templates]
12
11
  }
13
12
 
14
- Camping::S.sub! /autoload\s*:Template\s*,\s*['"]camping\/template['"]/, $TILT_CODE
13
+ Camping::S.sub!(/autoload\s*:Template\s*,\s*['"]camping\/template['"]/, $TILT_CODE)
15
14
  Camping::Apps.each do |c|
16
15
  c.module_eval $TILT_CODE
17
16
  end