heel 2.0.0 → 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.
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