vegas 0.0.4.1 → 0.1.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.
@@ -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