camping 2.1.532 → 3.0.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.
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