vegas 0.0.4.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,13 @@
1
+ == 0.1.0 2009-08-30
2
+
3
+ * New:
4
+ * options[:start] = false will keep the app from actually starting (useful for defining your own start/stop commands)
5
+ * options[:launch_path] Takes a string or an object that responds to call (proc/lambda) that gets the runner as its only argument. This allows you to easily manipulate options or args to launch the app to a specific path. See latest gembox for example.
6
+ * Changed:
7
+ * Sinatra is no longer a dependency! Vegas can now run pure Rack apps.
8
+ * All methods for starting an app are grouped into Runner#start
9
+ * launch! and start both take an optional path string to launch the app to.
10
+
1
11
  == 0.0.4 2009-08-09
2
12
 
3
13
  * new -L (--skip-launch) option doesn't launch the web browser (thanks bmabey!)
@@ -8,7 +8,7 @@ Vegas aims to solve the simple problem of creating executable versions of Sinatr
8
8
 
9
9
  == FEATURES/PROBLEMS:
10
10
 
11
- Currently, Vegas just includes a single class Vegas::Runner which wraps your Sinatra app to give it command line options, daemonization, PID/URL tracking, and browser launching (using Launchy).
11
+ Currently, Vegas just includes a single class Vegas::Runner which wraps your Sinatra app to give it command line options, daemon-ization, PID/URL tracking, and browser launching.
12
12
 
13
13
  Lets say you have a gem with a sinatra application. With Vegas you can create a bin that looks like
14
14
 
@@ -1,14 +1,14 @@
1
1
  begin
2
- require 'sinatra'
2
+ require 'rack'
3
3
  rescue LoadError
4
4
  require 'rubygems'
5
- require 'sinatra'
5
+ require 'rack'
6
6
  end
7
7
 
8
8
  $LOAD_PATH.unshift File.dirname(__FILE__)
9
9
 
10
10
  module Vegas
11
- VERSION = "0.0.4.1"
11
+ VERSION = "0.1.0"
12
12
  WINDOWS = !!(RUBY_PLATFORM =~ /(mingw|bccwin|wince|mswin32)/i)
13
13
 
14
14
  autoload :Runner, 'vegas/runner'
@@ -12,73 +12,82 @@ end
12
12
 
13
13
  module Vegas
14
14
  class Runner
15
- attr_reader :app, :app_name, :rack_handler, :port, :host, :options
16
-
15
+ attr_reader :app, :app_name, :rack_handler, :port, :host, :options, :args
16
+
17
17
  ROOT_DIR = File.expand_path(File.join('~', '.vegas'))
18
18
  PORT = 5678
19
19
  HOST = WINDOWS ? 'localhost' : '0.0.0.0'
20
-
21
- def initialize(app, app_name, set_options = {}, &block)
20
+
21
+ def initialize(app, app_name, set_options = {}, runtime_args = ARGV, &block)
22
22
  # initialize
23
- @app = app
24
- @app_name = app_name
25
- @options = set_options || {}
26
- @rack_handler = @app.send :detect_rack_handler
23
+ @app = app
24
+ @app_name = app_name
25
+ @options = set_options || {}
26
+ @runtime_args = runtime_args
27
+ self.class.logger.level = options[:debug] ? Logger::DEBUG : Logger::INFO
28
+
29
+ @rack_handler = @app.respond_to?(:detect_rack_handler) ?
30
+ @app.send(:detect_rack_handler) : Rack::Handler.get('thin')
27
31
  # load options from opt parser
28
- define_options do |opts|
32
+ @args = define_options do |opts|
29
33
  if block_given?
30
34
  opts.separator ''
31
35
  opts.separator "#{app_name} options:"
32
- yield(opts, app)
36
+ yield(self, opts, app)
33
37
  end
34
38
  end
39
+
35
40
  # set app options
36
41
  @host = options[:host] || HOST
37
- @app.set options
42
+ @app.set(options) if @app.respond_to?(:set)
38
43
  # initialize app dir
39
44
  FileUtils.mkdir_p(app_dir)
40
-
41
- logger.info "Running with Windows Settings" if WINDOWS
42
- logger.info "Starting #{app_name}"
43
-
44
- check_for_running
45
- find_port
46
- write_url
47
-
48
- begin
49
- launch!
50
- daemonize! unless options[:foreground]
51
- run!
52
- rescue RuntimeError => e
53
- logger.warn "There was an error starting #{app_name}: #{e}"
54
- exit
45
+ return if options[:start] === false
46
+ # evaluate the launch_path
47
+ path = if options[:launch_path] && options[:launch_path].respond_to?(:call)
48
+ options[:launch_path].call(self)
49
+ else
50
+ options[:launch_path]
55
51
  end
52
+ start(path)
56
53
  end
57
-
54
+
58
55
  def app_dir
59
56
  File.join(ROOT_DIR, app_name)
60
57
  end
61
-
58
+
62
59
  def pid_file
63
60
  File.join(app_dir, "#{app_name}.pid")
64
61
  end
65
-
62
+
66
63
  def url_file
67
64
  File.join(app_dir, "#{app_name}.url")
68
65
  end
69
-
66
+
70
67
  def url
71
68
  "http://#{host}:#{port}"
72
69
  end
73
-
70
+
74
71
  def log_file
75
72
  File.join(app_dir, "#{app_name}.log")
76
73
  end
77
-
78
- def handler_name
79
- rack_handler.name.gsub(/.*::/, '')
74
+
75
+ def start(path = nil)
76
+ logger.info "Running with Windows Settings" if WINDOWS
77
+ logger.info "Starting #{app_name}"
78
+ begin
79
+ check_for_running(path)
80
+ find_port
81
+ write_url
82
+ launch!(url, path)
83
+ daemonize! unless options[:foreground]
84
+ run!
85
+ rescue RuntimeError => e
86
+ logger.warn "There was an error starting #{app_name}: #{e}"
87
+ exit
88
+ end
80
89
  end
81
-
90
+
82
91
  def find_port
83
92
  if @port = options[:port]
84
93
  if !port_open?
@@ -93,7 +102,7 @@ module Vegas
93
102
  end
94
103
  end
95
104
  end
96
-
105
+
97
106
  def port_open?(check_url = nil)
98
107
  begin
99
108
  open(check_url || url)
@@ -102,22 +111,22 @@ module Vegas
102
111
  true
103
112
  end
104
113
  end
105
-
114
+
106
115
  def write_url
107
116
  File.open(url_file, 'w') {|f| f << url }
108
117
  end
109
-
110
- def check_for_running
118
+
119
+ def check_for_running(path = nil)
111
120
  if File.exists?(pid_file) && File.exists?(url_file)
112
121
  running_url = File.read(url_file)
113
122
  if !port_open?(running_url)
114
123
  logger.warn "#{app_name} is already running at #{running_url}"
115
- launch!(running_url)
124
+ launch!(running_url, path)
116
125
  exit!
117
126
  end
118
127
  end
119
128
  end
120
-
129
+
121
130
  def run!
122
131
  rack_handler.run app, :Host => host, :Port => port do |server|
123
132
  trap(kill_command) do
@@ -128,7 +137,7 @@ module Vegas
128
137
  end
129
138
  end
130
139
  end
131
-
140
+
132
141
  # Adapted from Rackup
133
142
  def daemonize!
134
143
  if RUBY_VERSION < "1.9"
@@ -149,13 +158,13 @@ module Vegas
149
158
  File.open(pid_file, 'w') {|f| f.write("#{Process.pid}") }
150
159
  at_exit { delete_pid! }
151
160
  end
152
-
153
- def launch!(specific_url = nil)
161
+
162
+ def launch!(specific_url = nil, path = nil)
154
163
  return if options[:skip_launch]
155
- cmd = WINDOWS ? "start" : "sleep 2 && open"
156
- system "#{cmd} #{specific_url || url}"
164
+ cmd = WINDOWS ? "start" : "open"
165
+ system "#{cmd} #{specific_url || url}#{path}"
157
166
  end
158
-
167
+
159
168
  def kill!
160
169
  pid = File.read(pid_file)
161
170
  logger.warn "Sending INT to #{pid.to_i}"
@@ -163,7 +172,7 @@ module Vegas
163
172
  rescue => e
164
173
  logger.warn "pid not found at #{pid_file} : #{e}"
165
174
  end
166
-
175
+
167
176
  def status
168
177
  if File.exists?(pid_file)
169
178
  logger.info "#{app_name} running"
@@ -174,26 +183,36 @@ module Vegas
174
183
  end
175
184
  end
176
185
 
177
- def logger
178
- return @logger if @logger
179
- @logger = Logger.new(STDOUT)
180
- @logger.level = options[:debug] ? Logger::DEBUG : Logger::INFO
181
- @logger.formatter = Proc.new {|s, t, n, msg| "[#{t}] #{msg}\n"}
186
+ def self.logger=(logger)
187
+ @logger = logger
188
+ end
189
+
190
+ def self.logger
191
+ @logger ||= LOGGER if defined?(LOGGER)
192
+ if !@logger
193
+ @logger = Logger.new(STDOUT)
194
+ @logger.formatter = Proc.new {|s, t, n, msg| "[#{t}] #{msg}\n"}
195
+ @logger
196
+ end
182
197
  @logger
183
198
  end
184
-
199
+
200
+ def logger
201
+ self.class.logger
202
+ end
203
+
185
204
  private
186
205
  def define_options
187
- OptionParser.new("", 24, ' ') { |opts|
206
+ OptionParser.new("", 24, ' ') do |opts|
188
207
  opts.banner = "Usage: #{app_name} [options]"
189
208
 
190
209
  opts.separator ""
191
210
  opts.separator "Vegas options:"
192
-
193
- opts.on("-s", "--server SERVER", "serve using SERVER (webrick/mongrel)") { |s|
211
+
212
+ opts.on("-s", "--server SERVER", "serve using SERVER (thin/mongrel/webrick)") { |s|
194
213
  @rack_handler = Rack::Handler.get(s)
195
214
  }
196
-
215
+
197
216
  opts.on("-o", "--host HOST", "listen on HOST (default: #{HOST})") { |host|
198
217
  @options[:host] = host
199
218
  }
@@ -218,18 +237,18 @@ module Vegas
218
237
  kill!
219
238
  exit
220
239
  }
221
-
240
+
222
241
  opts.on('-S', "--status", "display the current running PID and URL then quit") {|s|
223
242
  status
224
243
  exit!
225
244
  }
226
-
245
+
227
246
  opts.on('-d', "--debug", "raise the log level to :debug (default: :info)") {|s|
228
247
  @options[:debug] = true
229
248
  }
230
-
249
+
231
250
  yield opts if block_given?
232
-
251
+
233
252
  opts.separator ""
234
253
  opts.separator "Common options:"
235
254
 
@@ -242,24 +261,25 @@ module Vegas
242
261
  if app.respond_to?(:version)
243
262
  puts "#{app_name} #{app.version}"
244
263
  end
245
- puts "sinatra #{Sinatra::VERSION}"
264
+ puts "rack #{Rack::VERSION.join('.')}"
265
+ puts "sinatra #{Sinatra::VERSION}" if defined?(Sinatra)
246
266
  puts "vegas #{Vegas::VERSION}"
247
267
  exit
248
268
  end
249
269
 
250
- opts.parse! ARGV
251
- }
270
+ end.parse! @runtime_args
252
271
  rescue OptionParser::MissingArgument => e
253
272
  logger.warn "#{e}, run -h for options"
254
273
  exit
255
274
  end
256
-
275
+
257
276
  def kill_command
258
277
  WINDOWS ? 1 : :INT
259
278
  end
260
-
279
+
261
280
  def delete_pid!
262
281
  File.delete(pid_file) if File.exist?(pid_file)
263
282
  end
264
283
  end
284
+
265
285
  end
@@ -4,7 +4,7 @@ require 'sinatra'
4
4
  class TestApp < Sinatra::Base
5
5
 
6
6
  get '/' do
7
- 'This is a TEST'
7
+ 'This is a TEST: params: ' + params.inspect
8
8
  end
9
9
 
10
10
  end
@@ -1,4 +1,4 @@
1
- class TestApp1 < Sinatra::Default
1
+ class TestApp1 < Sinatra::Base
2
2
 
3
3
  get '/' do
4
4
  'TestApp1 Index'
@@ -10,7 +10,7 @@ class TestApp1 < Sinatra::Default
10
10
  end
11
11
 
12
12
 
13
- class TestApp2 < Sinatra::Default
13
+ class TestApp2 < Sinatra::Base
14
14
 
15
15
  get '/' do
16
16
  'TestApp2 Index'
@@ -19,4 +19,8 @@ class TestApp2 < Sinatra::Default
19
19
  get '/route' do
20
20
  'TestApp2 route'
21
21
  end
22
- end
22
+ end
23
+
24
+ RackApp1 = Proc.new {|env|
25
+ [200, {'Content-Type' => 'text/plain'}, ["This is an app. #{env.inspect}"]]
26
+ }
@@ -1,8 +1,8 @@
1
1
  dependencies = %w{
2
2
  bacon
3
+ mocha/standalone
4
+ mocha/object
3
5
  sinatra
4
- rack/test
5
- nokogiri
6
6
  }
7
7
 
8
8
  begin
@@ -13,10 +13,15 @@ rescue LoadError
13
13
  end
14
14
 
15
15
  require File.join(File.dirname(__FILE__), '..', 'lib', 'vegas.rb')
16
+ require File.join(File.dirname(__FILE__), 'test_apps.rb')
17
+
16
18
 
17
19
  module TestHelper
18
- def rackup(app)
19
- Rack::Test::Session.new(app)
20
+
21
+ def vegas(*args, &block)
22
+ Vegas::Runner.any_instance.stubs(:daemonize!).once
23
+ Rack::Handler::Thin.stubs(:run).once
24
+ @vegas = Vegas::Runner.new(*args, &block)
20
25
  end
21
26
 
22
27
  def body
@@ -26,6 +31,16 @@ module TestHelper
26
31
  def instance_of(klass)
27
32
  lambda {|obj| obj.is_a?(klass) }
28
33
  end
34
+
35
+ def exist_as_file
36
+ lambda {|obj| File.exist?(obj) }
37
+ end
38
+
39
+ def have_matching_file_content(content_regex)
40
+ lambda {|obj|
41
+ File.exist?(obj) && File.read(obj).match(content_regex)
42
+ }
43
+ end
29
44
 
30
45
  def html_body
31
46
  body =~ /^\<html/ ? body : "<html><body>#{body}</body></html>"
@@ -33,27 +48,4 @@ module TestHelper
33
48
 
34
49
  end
35
50
 
36
- Bacon::Context.send(:include, TestHelper)
37
-
38
- class Should
39
-
40
- def have_element(search, content = nil)
41
- satisfy "have element matching #{search}" do
42
- doc = Nokogiri.parse(@object.to_s)
43
- node_set = doc.search(search)
44
- if node_set.empty?
45
- false
46
- else
47
- collected_content = node_set.collect {|t| t.content }.join(' ')
48
- case content
49
- when Regexp
50
- collected_content =~ content
51
- when String
52
- collected_content.include?(content)
53
- when nil
54
- true
55
- end
56
- end
57
- end
58
- end
59
- end
51
+ Bacon::Context.send(:include, TestHelper)
@@ -1,8 +1,103 @@
1
1
  require File.join(File.dirname(__FILE__), 'test_helper.rb')
2
2
 
3
+ Vegas::Runner::ROOT_DIR = File.join(File.dirname(__FILE__), 'tmp', '.vegas')
4
+
3
5
  describe 'Vegas::Runner' do
4
-
5
-
6
+ before do
7
+ FileUtils.rm_rf(File.join(File.dirname(__FILE__), 'tmp'))
8
+ @log = StringIO.new
9
+ Vegas::Runner.logger = Logger.new(@log)
10
+ end
11
+
12
+ describe '.new' do
13
+
14
+ describe 'with basic usage' do
15
+ before do
16
+ Vegas::Runner.any_instance.expects(:system).once
17
+ vegas(TestApp1, 'vegas_test_app_1', {:sessions => true}, ["route","--debug"])
18
+ end
19
+
20
+ it "sets app" do
21
+ @vegas.app.should == TestApp1
22
+ end
23
+
24
+ it "sets app name" do
25
+ @vegas.app_name.should == 'vegas_test_app_1'
26
+ end
27
+
28
+ it "stores options" do
29
+ @vegas.options[:sessions].should.be.true
30
+ end
31
+
32
+ it "puts unparsed args into args" do
33
+ @vegas.args.should == ["route"]
34
+ end
35
+
36
+ it "parses options into @options" do
37
+ @vegas.options[:debug].should.be.true
38
+ end
39
+
40
+ it "writes the app dir" do
41
+ @vegas.app_dir.should exist_as_file
42
+ end
43
+
44
+ it "writes a url with the port" do
45
+ @vegas.url_file.should have_matching_file_content(/0.0.0.0\:#{@vegas.port}/)
46
+ end
47
+ end
48
+
49
+ describe 'with a sinatra app' do
50
+ before do
51
+ TestApp1.expects(:detect_rack_handler).returns(Rack::Handler::Mongrel)
52
+ Vegas::Runner.any_instance.expects(:system).once
53
+ Rack::Handler::Mongrel.stubs(:run)
54
+ vegas(TestApp1, 'vegas_test_app_1', {:skip_launch => true, :sessions => true}, ["route","--debug"])
55
+ end
56
+
57
+ it 'sets the rack handler automaticaly' do
58
+ @vegas.rack_handler.should == Rack::Handler::Mongrel
59
+ end
60
+
61
+ it "sets options on the app" do
62
+ @vegas.app.sessions.should.be.true
63
+ end
64
+
65
+ end
66
+
67
+ describe 'with a simple rack app' do
68
+ before do
69
+ vegas(RackApp1, 'rack_app_1', {:skip_launch => true, :sessions => true})
70
+ end
71
+
72
+ it "sets default rack handler to thin" do
73
+ @vegas.rack_handler.should == Rack::Handler::Thin
74
+ end
75
+ end
76
+
77
+ describe 'with a launch path specified as a proc' do
78
+ it 'evaluates the proc in the context of the runner' do
79
+ Vegas::Runner.any_instance.expects(:system).once.with {|s| s =~ /\?search\=blah$/ }
80
+ vegas(TestApp2,
81
+ 'vegas_test_app_2',
82
+ {:launch_path => Proc.new {|r| "?search=#{r.args.first}" }},
83
+ ["--debug", "blah"])
84
+ @vegas.options[:launch_path].should.be instance_of(Proc)
85
+ end
86
+ end
87
+
88
+ describe 'with a launch path specified as string' do
89
+ it 'launches to the specific path' do
90
+ Vegas::Runner.any_instance.expects(:system).once.with {|s| s =~ /\?search\=blah$/ }
91
+ vegas(TestApp2,
92
+ 'vegas_test_app_2',
93
+ {:launch_path => "?search=blah"},
94
+ ["--debug", "blah"])
95
+ @vegas.options[:launch_path].should == "?search=blah"
96
+ end
97
+ end
98
+
99
+
100
+ end
6
101
 
7
102
  end
8
103
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vegas
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aaron Quint
@@ -9,48 +9,38 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-08-09 00:00:00 -04:00
12
+ date: 2009-08-30 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
- name: sinatra
16
+ name: rack
17
17
  type: :runtime
18
18
  version_requirement:
19
19
  version_requirements: !ruby/object:Gem::Requirement
20
20
  requirements:
21
- - - ">="
21
+ - - "="
22
22
  - !ruby/object:Gem::Version
23
- version: 0.9.1
23
+ version: "1.0"
24
24
  version:
25
25
  - !ruby/object:Gem::Dependency
26
- name: newgem
27
- type: :development
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: 1.5.1
34
- version:
35
- - !ruby/object:Gem::Dependency
36
- name: nokogiri
26
+ name: bacon
37
27
  type: :development
38
28
  version_requirement:
39
29
  version_requirements: !ruby/object:Gem::Requirement
40
30
  requirements:
41
31
  - - ">="
42
32
  - !ruby/object:Gem::Version
43
- version: 1.0.6
33
+ version: 1.1.0
44
34
  version:
45
35
  - !ruby/object:Gem::Dependency
46
- name: bacon
36
+ name: mocha
47
37
  type: :development
48
38
  version_requirement:
49
39
  version_requirements: !ruby/object:Gem::Requirement
50
40
  requirements:
51
41
  - - ">="
52
42
  - !ruby/object:Gem::Version
53
- version: 1.1.0
43
+ version: 0.9.7
54
44
  version:
55
45
  - !ruby/object:Gem::Dependency
56
46
  name: hoe