heel 2.0.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/heel/mime_map.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  #--
2
- # Copyright (c) 2007, 2008 Jeremy Hinegardner
3
- # All rights reserved. Licensed under the BSD license. See LICENSE for details
2
+ # Copyright (c) 2007 - 2013 Jeremy Hinegardner
3
+ # All rights reserved. Licensed under the BSD license. See LICENSE for details
4
4
  #++
5
- #
5
+
6
6
  require 'mime/types'
7
7
 
8
8
  module Heel
data/lib/heel/rackapp.rb CHANGED
@@ -1,9 +1,8 @@
1
1
  #--
2
- # Copyright (c) 2007, 2008 Jeremy Hinegardner
3
- # All rights reserved. Licensed under the BSD license. See LICENSE for details
2
+ # Copyright (c) 2007 - 2013 Jeremy Hinegardner
3
+ # All rights reserved. Licensed under the BSD license. See LICENSE for details
4
4
  #++
5
5
 
6
- require 'heel'
7
6
  require 'rack'
8
7
  require 'rack/utils'
9
8
  require 'coderay'
@@ -20,7 +19,7 @@ module Heel
20
19
  attr_reader :ignore_globs
21
20
 
22
21
 
23
- def initialize(options = {})
22
+ def initialize(options = {})
24
23
  @ignore_globs = options[:ignore_globs] ||= %w( *~ .htaccess . )
25
24
  @document_root = options[:document_root] ||= Dir.pwd
26
25
  @directory_listing_allowed = options[:directory_listing_allowed] ||= true
@@ -48,7 +47,6 @@ module Heel
48
47
  end
49
48
 
50
49
  def directory_indexer
51
- indexer_ignore = ( ignore_globs + [ document_root] ).flatten
52
50
  @directory_indexer ||= DirectoryIndexer.new( directory_index_template_file, @options )
53
51
  end
54
52
 
@@ -67,13 +65,11 @@ module Heel
67
65
  dir_index = File.join(req.request_path, directory_index_html)
68
66
  if File.file?(dir_index) and File.readable?(dir_index) then
69
67
  response['Content-Type'] = mime_map.mime_type_of(dir_index).to_s
70
- response['Content-Length'] = File.size(dir_index).to_s
71
- response.body = File.open(dir_index)
68
+ response.write( File.read( dir_index ) )
72
69
  elsif directory_listing_allowed? then
73
70
  body = directory_indexer.index_page_for(req)
74
71
  response['Content-Type'] = 'text/html'
75
- response['Content-Length'] = body.length.to_s
76
- response.body << body
72
+ response.write( body )
77
73
  else
78
74
  return ::Heel::ErrorResponse.new(req.path_info,"Directory index is forbidden", 403).finish
79
75
  end
@@ -100,39 +96,30 @@ module Heel
100
96
  <head>
101
97
  <title>#{req.path_info}</title>
102
98
  <!-- CodeRay syntax highlighting CSS -->
103
- <link rel="stylesheet" href="/heel_css/coderay-cycnus.css" type="text/css" />
99
+ <link rel="stylesheet" href="/heel_css/coderay-alpha.css" type="text/css" />
104
100
  </head>
105
101
  <body>
106
- <div class="CodeRay">
107
- <pre>
108
- #{CodeRay.scan_file(req.request_path,:auto).html({:line_numbers => :inline})}
109
- </pre>
110
- </div>
102
+ #{CodeRay.scan_file(req.request_path,:auto).html({ :wrap => :div, :line_numbers => :inline })}
111
103
  </body>
112
104
  </html>
113
105
  EOM
114
106
  response['Content-Type'] = 'text/html'
115
107
  response['Content-Length'] = body.length.to_s
116
- response.body << body
108
+ response.write( body )
117
109
  return response.finish
118
110
  end
119
111
  end
120
112
 
121
113
  # fall through to a default file return
122
- #
123
114
 
124
115
  file_type = mime_map.mime_type_of(req.request_path)
125
116
  response['Content-Type'] = file_type.to_s
126
- response['Content-Length'] = req.stat.size.to_s
127
-
128
- return response.finish do
129
- File.open(req.request_path) do |f|
130
- while p = f.read(8192)
131
- response.write p
132
- end
117
+ File.open( req.request_path ) do |f|
118
+ while p = f.read( 8192 ) do
119
+ response.write( p )
133
120
  end
134
121
  end
135
-
122
+ return response.finish
136
123
  end
137
124
 
138
125
  # interface to rack, env is a hash
@@ -145,7 +132,7 @@ module Heel
145
132
  if req.forbidden? or should_ignore?(req.request_path) then
146
133
  return ErrorResponse.new(req.path_info,"You do not have permissionto view #{req.path_info}",403).finish
147
134
  end
148
- return ErrorResponse.new(req.path_info, "File not found: #{req.path_info}",403).finish unless req.found?
135
+ return ErrorResponse.new(req.path_info, "File not found: #{req.path_info}",404).finish unless req.found?
149
136
  return directory_index_response(req) if req.for_directory?
150
137
  return file_response(req) if req.for_file?
151
138
  else
data/lib/heel/request.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  #--
2
- # Copyright (c) 2007, 2008 Jeremy Hinegardner
3
- # All rights reserved. Licensed under the BSD license. See LICENSE for details
2
+ # Copyright (c) 2007 - 2013 Jeremy Hinegardner
3
+ # All rights reserved. Licensed under the BSD license. See LICENSE for details
4
4
  #++
5
- #
5
+
6
6
  require 'rack'
7
7
  module Heel
8
8
  # nothing more than a rack request with some additional methods and overriding
data/lib/heel/server.rb CHANGED
@@ -1,14 +1,13 @@
1
1
  #--
2
- # Copyright (c) 2007, 2008 Jeremy Hinegardner
3
- # All rights reserved. Licensed under the BSD license. See LICENSE for details
2
+ # Copyright (c) 2007 - 2013 Jeremy Hinegardner
3
+ # All rights reserved. Licensed under the BSD license. See LICENSE for details
4
4
  #++
5
5
 
6
- require 'heel'
7
- require 'thin'
8
6
  require 'ostruct'
9
7
  require 'launchy'
10
8
  require 'fileutils'
11
9
  require 'heel/rackapp'
10
+ require 'puma'
12
11
 
13
12
  module Heel
14
13
  class Server
@@ -39,34 +38,32 @@ module Heel
39
38
 
40
39
  set_io
41
40
 
42
- @options = default_options
43
- @parsed_options = ::OpenStruct.new
44
- @parser = option_parser
45
- @error_message = nil
41
+ @options = default_options
42
+ @parsed_options = ::OpenStruct.new
43
+ @parser = option_parser
44
+ @error_message = nil
46
45
 
47
46
  begin
48
47
  @parser.parse!(argv)
49
48
  rescue ::OptionParser::ParseError => pe
50
49
  msg = ["#{@parser.program_name}: #{pe}",
51
- "Try `#{@parser.program_name} --help` for more information"]
52
- @error_message = msg.join("\n")
50
+ "Try `#{@parser.program_name} --help` for more information"]
51
+ @error_message = msg.join("\n")
53
52
  end
54
53
  end
55
54
 
56
55
  def default_options
57
- if @default_options.nil? then
58
- @default_options = ::OpenStruct.new
59
- @default_options.show_version = false
60
- @default_options.show_help = false
61
- @default_options.address = "0.0.0.0"
62
- @default_options.port = 4331
63
- @default_options.document_root = Dir.pwd
64
- @default_options.daemonize = false
65
- @default_options.highlighting = false
66
- @default_options.kill = false
67
- @default_options.launch_browser = true
68
- end
69
- return @default_options
56
+ defaults = ::OpenStruct.new
57
+ defaults.show_version = false
58
+ defaults.show_help = false
59
+ defaults.address = "0.0.0.0"
60
+ defaults.port = 4331
61
+ defaults.document_root = Dir.pwd
62
+ defaults.daemonize = false
63
+ defaults.highlighting = false
64
+ defaults.kill = false
65
+ defaults.launch_browser = true
66
+ return defaults
70
67
  end
71
68
 
72
69
  def default_directory
@@ -81,6 +78,14 @@ module Heel
81
78
  File.join(default_directory,"heel.log")
82
79
  end
83
80
 
81
+ def win?
82
+ RUBY_PLATFORM =~ /mswin|mingw/
83
+ end
84
+
85
+ def java?
86
+ RUBY_PLATFORM =~ /java/
87
+ end
88
+
84
89
  def option_parser
85
90
  OptionParser.new do |op|
86
91
  op.separator ""
@@ -88,10 +93,11 @@ module Heel
88
93
  op.on("-a", "--address ADDRESS", "Address to bind to",
89
94
  " (default: #{default_options.address})") do |add|
90
95
  @parsed_options.address = add
91
- end
96
+ end
92
97
 
93
98
  op.on("-d", "--daemonize", "Run daemonized in the background") do
94
- raise ::OptionParser::ParseError, "Daemonizing is not supported on windows" if Thin.win?
99
+ raise ::OptionParser::ParseError, "Daemonizing is not supported on windows" if win?
100
+ raise ::OptionParser::ParseError, "Daemonizing is not supported on java" if java?
95
101
  @parsed_options.daemonize = true
96
102
  end
97
103
 
@@ -106,23 +112,23 @@ module Heel
106
112
  op.on("--[no-]highlighting", "Turn on or off syntax highlighting",
107
113
  " (default: off)") do |highlighting|
108
114
  @parsed_options.highlighting = highlighting
109
- end
115
+ end
110
116
 
111
117
  op.on("--[no-]launch-browser", "Turn on or off automatic browser launch",
112
118
  " (default: on)") do |l|
113
119
  @parsed_options.launch_browser = l
114
- end
120
+ end
115
121
 
116
122
  op.on("-p", "--port PORT", Integer, "Port to bind to",
117
123
  " (default: #{default_options.port})") do |port|
118
124
  @parsed_options.port = port
119
- end
125
+ end
120
126
 
121
127
  op.on("-r","--root ROOT",
122
128
  "Set the document root"," (default: #{default_options.document_root})") do |document_root|
123
129
  @parsed_options.document_root = File.expand_path(document_root)
124
130
  raise ::OptionParser::ParseError, "#{@parsed_options.document_root} is not a valid directory" if not File.directory?(@parsed_options.document_root)
125
- end
131
+ end
126
132
 
127
133
  op.on("-v", "--version", "Show version") do
128
134
  @parsed_options.show_version = true
@@ -132,9 +138,7 @@ module Heel
132
138
 
133
139
  def merge_options
134
140
  options = default_options.marshal_dump
135
- @parsed_options.marshal_dump.each_pair do |key,value|
136
- options[key] = value
137
- end
141
+ options.merge!( @parsed_options.marshal_dump )
138
142
 
139
143
  @options = OpenStruct.new(options)
140
144
  end
@@ -174,7 +178,7 @@ module Heel
174
178
  rescue Errno::ESRCH
175
179
  @stdout.puts "Unable to kill process with pid #{pid}. Process does not exist. Removing stale pid file."
176
180
  File.unlink(pid_file)
177
- rescue Errno::EPERM
181
+ rescue Errno::EPERM
178
182
  @stdout.puts "Unable to kill process with pid #{pid}. No permissions to kill process."
179
183
  end
180
184
  else
@@ -197,7 +201,7 @@ module Heel
197
201
  # make sure that if we are daemonizing the process is not running
198
202
  def ensure_not_running
199
203
  if options.daemonize and File.exist?(pid_file) then
200
- @stdout.puts "ERROR: PID File #{pid_file} already exists. Heel may already be running."
204
+ @stdout.puts "ERROR: PID File #{pid_file} already exists. Heel may already be running."
201
205
  @stdout.puts "ERROR: Check the Log file #{log_file}"
202
206
  @stdout.puts "ERROR: Heel will not start until the .pid file is cleared (`heel --kill' to clean it up)."
203
207
  exit 1
@@ -205,7 +209,7 @@ module Heel
205
209
  end
206
210
 
207
211
  def launch_browser
208
- Thread.new do
212
+ Thread.new do
209
213
  print "Launching your browser"
210
214
  if options.daemonize then
211
215
  puts " at http://#{options.address}:#{options.port}/"
@@ -216,24 +220,11 @@ module Heel
216
220
  end
217
221
  end
218
222
 
219
- def thin_server
220
- server = Thin::Server.new(options.address, options.port)
221
-
222
- # overload the name of the process so it shows up as heel not thin
223
- def server.name
224
- "heel (v#{Heel::VERSION})"
225
- end
226
-
227
- server.pid_file = pid_file
228
- server.log_file = log_file
229
-
223
+ def heel_app
230
224
  app = Heel::RackApp.new({ :document_root => options.document_root,
231
225
  :highlighting => options.highlighting})
232
-
233
- Heel::Logger.log_file = log_file
234
- server.app = Rack::Builder.new {
235
- use Heel::Logger
236
- map "/" do
226
+ stack = Rack::Builder.new {
227
+ map "/" do
237
228
  run app
238
229
  end
239
230
  map "/heel_css" do
@@ -242,40 +233,62 @@ module Heel
242
233
  map "/heel_icons" do
243
234
  run Rack::File.new(Heel::Configuration.data_path("famfamfam", "icons"))
244
235
  end
245
-
246
236
  }
247
-
248
- server.app = Thin::Stats::Adapter.new(server.app, "/heel_stats")
249
-
250
- return server
237
+ return stack.to_app
251
238
  end
252
239
 
253
- def start_thin_server
254
- server = thin_server
240
+ def start_server
241
+ server_thread = Thread.new do
242
+ if options.daemonize then
243
+ if cpid = fork then
244
+ Process.waitpid( cpid )
245
+ else
246
+ server = Rack::Server.new( server_options )
247
+ server.start
248
+ end
249
+ else
250
+ server = Rack::Server.new( server_options )
251
+ server.start
252
+ end
253
+ end
254
+ return server_thread
255
+ end
255
256
 
257
+ def start_server_old
258
+ server = Rack::Server.new( server_options )
256
259
  server_thread = Thread.new do
257
- begin
258
- if options.daemonize then
259
- if cpid = fork then
260
- # wait for the top child of the server double fork to exit
261
- Process.waitpid(cpid)
262
- else
263
- server.daemonize
264
- server.start
265
- end
260
+ if options.daemonize then
261
+ if cpid = fork then
262
+ # wait for the server to span and then move on to launching the
263
+ # browser
264
+ Process.waitpid( cpid )
266
265
  else
267
- begin
268
- server.start
269
- rescue RuntimeError
270
- $stderr.puts "ERROR: Unable to start server. Heel may already be running. Please check running processes or run `heel --kill'"
271
- exit 1
272
- end
266
+ server.start
267
+ end
268
+ else
269
+ begin
270
+ server.start
271
+ rescue RuntimeError
272
+ $stderr.puts "ERROR: Unable to start server. Heel may already be running. Please check running processes or run `heel --kill'"
273
+ exit 1
273
274
  end
274
275
  end
275
276
  end
277
+ return server_thread
278
+ end
279
+
280
+ def server_options
281
+ {
282
+ :app => heel_app,
283
+ :pid => pid_file,
284
+ :Port => options.port,
285
+ :Host => options.address,
286
+ :environment => 'deployment',
287
+ :server => 'puma',
288
+ :daemonize => options.daemonize
289
+ }
276
290
  end
277
291
 
278
-
279
292
  # run the heel server with the current options.
280
293
  def run
281
294
 
@@ -284,7 +297,7 @@ module Heel
284
297
  setup_heel_dir
285
298
  ensure_not_running
286
299
 
287
- server_thread = start_thin_server
300
+ server_thread = start_server
288
301
 
289
302
  if options.launch_browser then
290
303
  launch_browser.join
@@ -1,20 +1,24 @@
1
- require 'spec/spec_helper'
1
+ require 'spec_helper'
2
+ require 'pathname'
2
3
 
3
4
  describe Heel::Configuration do
5
+ before do
6
+ @proj_root = Pathname.new( __FILE__ ).parent.parent
7
+ end
4
8
  it "finds files relative to root of gem" do
5
- Heel::Configuration.root_dir.should == File.expand_path(File.join(File.dirname(__FILE__), "..")) + "/"
9
+ Heel::Configuration.root_dir.must_equal @proj_root.expand_path.to_s + File::SEPARATOR
6
10
  end
7
11
 
8
12
  it "finds files in the config dir of the project" do
9
- Heel::Configuration.config_path('config.rb').should == File.expand_path(File.join(File.dirname(__FILE__), "..", "config", "config.rb"))
13
+ Heel::Configuration.config_path('config.rb').must_equal @proj_root.join("config", "config.rb").to_s
10
14
  end
11
15
 
12
16
  it "finds files in the data dir of the project" do
13
- Heel::Configuration.data_path('famfamfam', 'icons').should == File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "famfamfam", "icons"))
17
+ Heel::Configuration.data_path('famfamfam', 'icons').must_equal @proj_root.join( "data", "famfamfam", "icons" ).to_s
14
18
  end
15
19
 
16
20
  it "finds files in the lib dir of the project" do
17
- Heel::Configuration.lib_path('heel.rb').should == File.expand_path(File.join(File.dirname(__FILE__), "..", "lib", "heel.rb"))
21
+ Heel::Configuration.lib_path('heel.rb').must_equal @proj_root.join("lib", "heel.rb").to_s
18
22
  end
19
23
 
20
24
  end
@@ -1,4 +1,4 @@
1
- require 'spec/spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe Heel::DirectoryIndexer do
4
4
  before(:each) do
@@ -7,28 +7,28 @@ describe Heel::DirectoryIndexer do
7
7
 
8
8
  it "should ignore .htaccess files" do
9
9
  @indexer.options[:ignore_globs] = %w( *~ .htaccess . )
10
- @indexer.should_ignore?(".htaccess").should == true
10
+ @indexer.should_ignore?(".htaccess").must_equal true
11
11
  end
12
12
 
13
13
  it "should not ignore .html files " do
14
14
  @indexer.options[:ignore_globs] = %w( *~ .htaccess . )
15
- @indexer.should_ignore?("something.html").should == false
15
+ @indexer.should_ignore?("something.html").must_equal false
16
16
  end
17
17
 
18
18
  it "can tell if highlighting is to be performed" do
19
- @indexer.should be_highlighting
19
+ @indexer.must_be :highlighting?
20
20
  end
21
21
 
22
22
  it "knows if the template should be reloaded on changes" do
23
- @indexer.should_not be_reload_on_template_change
23
+ @indexer.reload_on_template_change?.must_equal false
24
24
  end
25
25
 
26
- it "may or maynot use icons" do
27
- @indexer.should_not be_using_icons
26
+ it "uses icons" do
27
+ @indexer.using_icons?.must_equal false
28
28
  end
29
29
 
30
30
  it "uses a mime map" do
31
- @indexer.mime_map.should be_instance_of(Heel::MimeMap)
31
+ @indexer.mime_map.must_be_instance_of(Heel::MimeMap)
32
32
  end
33
33
 
34
34
  end