foreman 0.29.0 → 0.37.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,4 +1,5 @@
1
1
  require "foreman"
2
+ require "rubygems"
2
3
 
3
4
  class Foreman::Process
4
5
 
@@ -14,10 +15,8 @@ class Foreman::Process
14
15
  end
15
16
 
16
17
  def run(pipe, basedir, environment)
17
- Dir.chdir(basedir) do
18
- with_environment(environment.merge("PORT" => port.to_s)) do
19
- run_process entry.command, pipe
20
- end
18
+ with_environment(environment.merge("PORT" => port.to_s)) do
19
+ run_process basedir, entry.command, pipe
21
20
  end
22
21
  end
23
22
 
@@ -25,12 +24,52 @@ class Foreman::Process
25
24
  "%s.%s" % [ entry.name, num ]
26
25
  end
27
26
 
27
+ def kill(signal)
28
+ pid && Process.kill(signal, pid)
29
+ rescue Errno::ESRCH
30
+ false
31
+ end
32
+
33
+ def detach
34
+ pid && Process.detach(pid)
35
+ end
36
+
37
+ def alive?
38
+ kill(0)
39
+ end
40
+
41
+ def dead?
42
+ !alive?
43
+ end
44
+
28
45
  private
29
46
 
30
- def run_process(command, pipe)
31
- io = IO.popen([Foreman.runner, replace_command_env(command)], "w+")
32
- @pid = io.pid
33
- trap("SIGTERM") { "got sigterm for %d" % @pid }
47
+ def fork_with_io(command, basedir)
48
+ reader, writer = IO.pipe
49
+ command = replace_command_env(command)
50
+ pid = if Foreman.windows?
51
+ Dir.chdir(basedir) do
52
+ Process.spawn command, :out => writer, :err => writer
53
+ end
54
+ elsif Foreman.jruby?
55
+ require "posix/spawn"
56
+ POSIX::Spawn.spawn(Foreman.runner, "-d", basedir, command, {
57
+ :out => writer, :err => writer
58
+ })
59
+ else
60
+ fork do
61
+ writer.sync = true
62
+ $stdout.reopen writer
63
+ $stderr.reopen writer
64
+ reader.close
65
+ exec Foreman.runner, "-d", basedir, command
66
+ end
67
+ end
68
+ [ reader, pid ]
69
+ end
70
+
71
+ def run_process(basedir, command, pipe)
72
+ io, @pid = fork_with_io(command, basedir)
34
73
  output pipe, "started with pid %d" % @pid
35
74
  Thread.new do
36
75
  until io.eof?
@@ -48,12 +87,10 @@ private
48
87
  end
49
88
 
50
89
  def with_environment(environment)
51
- old_env = ENV.each_pair.inject({}) { |h,(k,v)| h.update(k => v) }
52
- environment.each { |k,v| ENV[k] = v }
53
- ret = yield
54
- ENV.clear
55
- old_env.each { |k,v| ENV[k] = v}
56
- ret
90
+ original = ENV.to_hash
91
+ ENV.update environment
92
+ yield
93
+ ensure
94
+ ENV.replace original
57
95
  end
58
-
59
96
  end
data/lib/foreman/utils.rb CHANGED
@@ -5,7 +5,10 @@ class Foreman::Utils
5
5
  def self.parse_concurrency(concurrency)
6
6
  begin
7
7
  pairs = concurrency.to_s.gsub(/\s/, "").split(",")
8
- pairs.inject(Hash.new(1)) do |hash, pair|
8
+
9
+ default = concurrency.nil? ? 1 : 0
10
+
11
+ pairs.inject(Hash.new(default)) do |hash, pair|
9
12
  process, amount = pair.split("=")
10
13
  hash.update(process => amount.to_i)
11
14
  end
@@ -1,5 +1,5 @@
1
1
  module Foreman
2
2
 
3
- VERSION = "0.29.0"
3
+ VERSION = "0.37.0"
4
4
 
5
5
  end
data/lib/foreman.rb CHANGED
@@ -14,5 +14,12 @@ module Foreman
14
14
  File.expand_path("../../bin/runner", __FILE__)
15
15
  end
16
16
 
17
- end
17
+ def self.jruby?
18
+ defined?(RUBY_PLATFORM) and RUBY_PLATFORM == "java"
19
+ end
18
20
 
21
+ def self.windows?
22
+ defined?(RUBY_PLATFORM) and RUBY_PLATFORM =~ /(win|w)32$/
23
+ end
24
+
25
+ end
data/man/foreman.1 CHANGED
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "FOREMAN" "1" "November 2011" "Foreman 0.26.0" "Foreman Manual"
4
+ .TH "FOREMAN" "1" "January 2012" "Foreman 0.33.1" "Foreman Manual"
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBforeman\fR \- manage Procfile\-based applications
@@ -68,6 +68,10 @@ Specify the user the application should be run as\. Defaults to the app name
68
68
  These options control all modes of foreman\'s operation\.
69
69
  .
70
70
  .TP
71
+ \fB\-d\fR, \fB\-\-directory\fR
72
+ Specify an alternate application root\. This defaults to the directory containing the Procfile\.
73
+ .
74
+ .TP
71
75
  \fB\-e\fR, \fB\-\-env\fR
72
76
  Specify an alternate environment file\. You can specify more than one file by using: \fB\-\-env file1,file2\fR\.
73
77
  .
@@ -1,7 +1,7 @@
1
1
  require "spec_helper"
2
2
  require "foreman/cli"
3
3
 
4
- describe "Foreman::CLI" do
4
+ describe "Foreman::CLI", :fakefs do
5
5
  subject { Foreman::CLI.new }
6
6
 
7
7
  describe "start" do
@@ -27,10 +27,21 @@ describe "Foreman::CLI" do
27
27
 
28
28
  describe "export" do
29
29
  describe "options" do
30
+ it "uses .foreman" do
31
+ write_procfile
32
+ File.open(".foreman", "w") { |f| f.puts "concurrency: alpha=2" }
33
+ mock_export = mock(Foreman::Export::Upstart)
34
+ mock(Foreman::Export::Upstart).new("/upstart", is_a(Foreman::Engine), { "concurrency" => "alpha=2" }) { mock_export }
35
+ mock_export.export
36
+ foreman %{ export upstart /upstart }
37
+ end
38
+
30
39
  it "respects --env" do
31
40
  write_procfile
32
41
  write_env("envfile")
33
- mock.instance_of(Foreman::Export::Upstart).export("/upstart", { "env" => "envfile" })
42
+ mock_export = mock(Foreman::Export::Upstart)
43
+ mock(Foreman::Export::Upstart).new("/upstart", is_a(Foreman::Engine), { "env" => "envfile" }) { mock_export }
44
+ mock_export.export
34
45
  foreman %{ export upstart /upstart --env envfile }
35
46
  end
36
47
  end
@@ -47,10 +58,18 @@ describe "Foreman::CLI" do
47
58
  describe "with a Procfile" do
48
59
  before(:each) { write_procfile }
49
60
 
50
- describe "with an invalid formatter" do
61
+ describe "with a formatter with a generic error" do
62
+ before do
63
+ mock(Foreman::Export).formatter("errorful") { Class.new(Foreman::Export::Base) do
64
+ def export
65
+ raise Foreman::Export::Exception.new("foo")
66
+ end
67
+ end }
68
+ end
69
+
51
70
  it "prints an error" do
52
- mock_error(subject, "Unknown export format: invalidformatter.") do
53
- subject.export("invalidformatter")
71
+ mock_error(subject, "foo") do
72
+ subject.export("errorful")
54
73
  end
55
74
  end
56
75
  end
@@ -60,7 +79,9 @@ describe "Foreman::CLI" do
60
79
 
61
80
  it "runs successfully" do
62
81
  dont_allow(subject).error
63
- mock.instance_of(Foreman::Export::Upstart).export("/tmp/foo", {})
82
+ mock_export = mock(Foreman::Export::Upstart)
83
+ mock(Foreman::Export::Upstart).new("/tmp/foo", is_a(Foreman::Engine), {}) { mock_export }
84
+ mock_export.export
64
85
  subject.export("upstart", "/tmp/foo")
65
86
  end
66
87
  end
@@ -72,7 +93,7 @@ describe "Foreman::CLI" do
72
93
  before { write_procfile }
73
94
 
74
95
  it "displays the jobs" do
75
- mock(subject).display("valid procfile detected (alpha, bravo)")
96
+ mock(subject).puts("valid procfile detected (alpha, bravo)")
76
97
  subject.check
77
98
  end
78
99
  end
@@ -90,4 +111,53 @@ describe "Foreman::CLI" do
90
111
  end
91
112
  end
92
113
 
114
+ describe "run" do
115
+ describe "with a valid Procfile" do
116
+ before { write_procfile }
117
+
118
+ describe "and a command" do
119
+ let(:command) { ["ls", "-l"] }
120
+
121
+ before(:each) do
122
+ stub(subject).exec
123
+ end
124
+
125
+ it "should load the environment file" do
126
+ write_env
127
+ preserving_env do
128
+ subject.run *command
129
+ ENV["FOO"].should == "bar"
130
+ end
131
+
132
+ ENV["FOO"].should be_nil
133
+ end
134
+
135
+ it "should runute the command as a string" do
136
+ mock(subject).exec(command.join(" "))
137
+ subject.run *command
138
+ end
139
+ end
140
+
141
+ describe "and a non-existent command" do
142
+ let(:command) { "iuhtngrglhulhdfg" }
143
+
144
+ it "should print an error" do
145
+ mock_error(subject, "command not found: #{command}") do
146
+ subject.run command
147
+ end
148
+ end
149
+ end
150
+
151
+ describe "and a non-executable command" do
152
+ let(:command) { __FILE__ }
153
+
154
+ it "should print an error" do
155
+ mock_error(subject, "not executable: #{command}") do
156
+ subject.run command
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end
162
+
93
163
  end
@@ -1,7 +1,7 @@
1
1
  require "spec_helper"
2
2
  require "foreman/engine"
3
3
 
4
- describe "Foreman::Engine" do
4
+ describe "Foreman::Engine", :fakefs do
5
5
  subject { Foreman::Engine.new("Procfile", {}) }
6
6
 
7
7
  describe "initialize" do
@@ -24,8 +24,8 @@ describe "Foreman::Engine" do
24
24
  describe "start" do
25
25
  it "forks the processes" do
26
26
  write_procfile
27
- mock.instance_of(Foreman::Process).run_process("./alpha", is_a(IO))
28
- mock.instance_of(Foreman::Process).run_process("./bravo", is_a(IO))
27
+ mock.instance_of(Foreman::Process).run_process(Dir.pwd, "./alpha", is_a(IO))
28
+ mock.instance_of(Foreman::Process).run_process(Dir.pwd, "./bravo", is_a(IO))
29
29
  mock(subject).watch_for_output
30
30
  mock(subject).watch_for_termination
31
31
  subject.start
@@ -34,8 +34,8 @@ describe "Foreman::Engine" do
34
34
  it "handles concurrency" do
35
35
  write_procfile
36
36
  engine = Foreman::Engine.new("Procfile",:concurrency => "alpha=2")
37
- mock.instance_of(Foreman::Process).run_process("./alpha", is_a(IO)).twice
38
- mock.instance_of(Foreman::Process).run_process("./bravo", is_a(IO))
37
+ mock.instance_of(Foreman::Process).run_process(Dir.pwd, "./alpha", is_a(IO)).twice
38
+ mock.instance_of(Foreman::Process).run_process(Dir.pwd, "./bravo", is_a(IO)).never
39
39
  mock(engine).watch_for_output
40
40
  mock(engine).watch_for_termination
41
41
  engine.start
@@ -0,0 +1,22 @@
1
+ require "spec_helper"
2
+ require "foreman/export/base"
3
+
4
+ describe "Foreman::Export::Base" do
5
+ let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
6
+ let(:location) { "/tmp/init" }
7
+ let(:engine) { Foreman::Engine.new(procfile) }
8
+ let(:subject) { Foreman::Export::Base.new(location, engine) }
9
+
10
+ it "has a say method for displaying info" do
11
+ mock(subject).puts("[foreman export] foo")
12
+ subject.send(:say, "foo")
13
+ end
14
+
15
+ it "export needs to be overridden" do
16
+ lambda { subject.export }.should raise_error("export method must be overridden")
17
+ end
18
+
19
+ it "raises errors as a Foreman::Export::Exception" do
20
+ lambda { subject.send(:error, "foo") }.should raise_error(Foreman::Export::Exception, "foo")
21
+ end
22
+ end
@@ -3,17 +3,34 @@ require "foreman/engine"
3
3
  require "foreman/export/bluepill"
4
4
  require "tmpdir"
5
5
 
6
- describe Foreman::Export::Bluepill do
6
+ describe Foreman::Export::Bluepill, :fakefs do
7
7
  let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
8
- let(:engine) { Foreman::Engine.new(procfile) }
9
- let(:bluepill) { Foreman::Export::Bluepill.new(engine) }
8
+ let(:engine) { Foreman::Engine.new(procfile) }
9
+ let(:options) { Hash.new }
10
+ let(:bluepill) { Foreman::Export::Bluepill.new("/tmp/init", engine, options) }
10
11
 
11
12
  before(:each) { load_export_templates_into_fakefs("bluepill") }
12
13
  before(:each) { stub(bluepill).say }
13
14
 
14
15
  it "exports to the filesystem" do
15
- bluepill.export("/tmp/init", :concurrency => "alpha=2")
16
- File.read("/tmp/init/app.pill").should == example_export_file("bluepill/app.pill")
16
+ bluepill.export
17
+ normalize_space(File.read("/tmp/init/app.pill")).should == normalize_space(example_export_file("bluepill/app.pill"))
18
+ end
19
+
20
+ it "cleans up if exporting into an existing dir" do
21
+ mock(FileUtils).rm("/tmp/init/app.pill")
22
+
23
+ bluepill.export
24
+ bluepill.export
25
+ end
26
+
27
+ context "with concurrency" do
28
+ let(:options) { Hash[:concurrency => "alpha=2"] }
29
+
30
+ it "exports to the filesystem with concurrency" do
31
+ bluepill.export
32
+ normalize_space(File.read("/tmp/init/app.pill")).should == normalize_space(example_export_file("bluepill/app-concurrency.pill"))
33
+ end
17
34
  end
18
35
 
19
36
  end
@@ -0,0 +1,40 @@
1
+ require "spec_helper"
2
+ require "foreman/engine"
3
+ require "foreman/export/inittab"
4
+ require "tmpdir"
5
+
6
+ describe Foreman::Export::Inittab, :fakefs do
7
+ let(:location) { "/tmp/inittab" }
8
+ let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
9
+ let(:location) { "/tmp/inittab" }
10
+ let(:engine) { Foreman::Engine.new(procfile) }
11
+ let(:options) { Hash.new }
12
+ let(:inittab) { Foreman::Export::Inittab.new(location, engine, options) }
13
+
14
+ before(:each) { load_export_templates_into_fakefs("inittab") }
15
+ before(:each) { stub(inittab).say }
16
+
17
+ it "exports to the filesystem" do
18
+ inittab.export
19
+ File.read("/tmp/inittab").should == example_export_file("inittab/inittab.default")
20
+ end
21
+
22
+ context "to stdout" do
23
+ let(:location) { "-" }
24
+
25
+ it "exports to stdout" do
26
+ mock(inittab).puts example_export_file("inittab/inittab.default")
27
+ inittab.export
28
+ end
29
+ end
30
+
31
+ context "with concurrency" do
32
+ let(:options) { Hash[:concurrency => "alpha=2"] }
33
+
34
+ it "exports to the filesystem with concurrency" do
35
+ inittab.export
36
+ File.read("/tmp/inittab").should == example_export_file("inittab/inittab.concurrency")
37
+ end
38
+ end
39
+
40
+ end
@@ -3,33 +3,39 @@ require "foreman/engine"
3
3
  require "foreman/export/runit"
4
4
  require "tmpdir"
5
5
 
6
- describe Foreman::Export::Runit do
6
+ describe Foreman::Export::Runit, :fakefs do
7
7
  let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile", 'bar=baz') }
8
8
  let(:engine) { Foreman::Engine.new(procfile) }
9
- let(:runit) { Foreman::Export::Runit.new(engine) }
10
-
9
+ let(:runit) { Foreman::Export::Runit.new('/tmp/init', engine, :concurrency => 'alpha=2,bravo=1') }
10
+
11
11
  before(:each) { load_export_templates_into_fakefs("runit") }
12
12
  before(:each) { stub(runit).say }
13
-
13
+ before(:each) { stub(FakeFS::FileUtils).chmod }
14
+
14
15
  it "exports to the filesystem" do
15
16
  FileUtils.mkdir_p('/tmp/init')
16
- runit.export('/tmp/init', :concurrency => 'alpha=2')
17
-
17
+
18
+ runit.export
19
+
18
20
  File.read("/tmp/init/app-alpha-1/run").should == example_export_file('runit/app-alpha-1-run')
19
- File.read("/tmp/init/app-alpha-1/log/run").should ==
21
+ File.read("/tmp/init/app-alpha-1/log/run").should ==
20
22
  example_export_file('runit/app-alpha-1-log-run')
21
23
  File.read("/tmp/init/app-alpha-1/env/PORT").should == "5000\n"
22
24
  File.read("/tmp/init/app-alpha-1/env/BAR").should == "baz\n"
23
-
25
+
24
26
  File.read("/tmp/init/app-alpha-2/run").should == example_export_file('runit/app-alpha-2-run')
25
- File.read("/tmp/init/app-alpha-2/log/run").should ==
27
+ File.read("/tmp/init/app-alpha-2/log/run").should ==
26
28
  example_export_file('runit/app-alpha-2-log-run')
27
29
  File.read("/tmp/init/app-alpha-2/env/PORT").should == "5001\n"
28
30
  File.read("/tmp/init/app-alpha-2/env/BAR").should == "baz\n"
29
-
31
+
30
32
  File.read("/tmp/init/app-bravo-1/run").should == example_export_file('runit/app-bravo-1-run')
31
- File.read("/tmp/init/app-bravo-1/log/run").should ==
33
+ File.read("/tmp/init/app-bravo-1/log/run").should ==
32
34
  example_export_file('runit/app-bravo-1-log-run')
33
35
  File.read("/tmp/init/app-bravo-1/env/PORT").should == "5100\n"
34
36
  end
35
- end
37
+
38
+ it "creates a full path to the export directory" do
39
+ expect { runit.export }.to_not raise_error(Errno::ENOENT)
40
+ end
41
+ end
@@ -3,27 +3,53 @@ require "foreman/engine"
3
3
  require "foreman/export/upstart"
4
4
  require "tmpdir"
5
5
 
6
- describe Foreman::Export::Upstart do
6
+ describe Foreman::Export::Upstart, :fakefs do
7
7
  let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
8
- let(:engine) { Foreman::Engine.new(procfile) }
9
- let(:upstart) { Foreman::Export::Upstart.new(engine) }
8
+ let(:engine) { Foreman::Engine.new(procfile) }
9
+ let(:options) { Hash.new }
10
+ let(:upstart) { Foreman::Export::Upstart.new("/tmp/init", engine, options) }
10
11
 
11
12
  before(:each) { load_export_templates_into_fakefs("upstart") }
12
13
  before(:each) { stub(upstart).say }
13
14
 
14
15
  it "exports to the filesystem" do
15
- upstart.export("/tmp/init", :concurrency => "alpha=2")
16
+ upstart.export
16
17
 
17
18
  File.read("/tmp/init/app.conf").should == example_export_file("upstart/app.conf")
18
19
  File.read("/tmp/init/app-alpha.conf").should == example_export_file("upstart/app-alpha.conf")
19
20
  File.read("/tmp/init/app-alpha-1.conf").should == example_export_file("upstart/app-alpha-1.conf")
20
- File.read("/tmp/init/app-alpha-2.conf").should == example_export_file("upstart/app-alpha-2.conf")
21
21
  File.read("/tmp/init/app-bravo.conf").should == example_export_file("upstart/app-bravo.conf")
22
22
  File.read("/tmp/init/app-bravo-1.conf").should == example_export_file("upstart/app-bravo-1.conf")
23
23
  end
24
24
 
25
+ it "cleans up if exporting into an existing dir" do
26
+ mock(FileUtils).rm("/tmp/init/app.conf")
27
+ mock(FileUtils).rm("/tmp/init/app-alpha.conf")
28
+ mock(FileUtils).rm("/tmp/init/app-alpha-1.conf")
29
+ mock(FileUtils).rm("/tmp/init/app-bravo.conf")
30
+ mock(FileUtils).rm("/tmp/init/app-bravo-1.conf")
31
+
32
+ upstart.export
33
+ upstart.export
34
+ end
35
+
36
+ context "with concurrency" do
37
+ let(:options) { Hash[:concurrency => "alpha=2"] }
38
+
39
+ it "exports to the filesystem with concurrency" do
40
+ upstart.export
41
+
42
+ File.read("/tmp/init/app.conf").should == example_export_file("upstart/app.conf")
43
+ File.read("/tmp/init/app-alpha.conf").should == example_export_file("upstart/app-alpha.conf")
44
+ File.read("/tmp/init/app-alpha-1.conf").should == example_export_file("upstart/app-alpha-1.conf")
45
+ File.read("/tmp/init/app-alpha-2.conf").should == example_export_file("upstart/app-alpha-2.conf")
46
+ File.exists?("/tmp/init/app-bravo-1.conf").should == false
47
+ end
48
+ end
49
+
25
50
  context "with alternate templates" do
26
51
  let(:template_root) { "/tmp/alternate" }
52
+ let(:upstart) { Foreman::Export::Upstart.new("/tmp/init", engine, :template => template_root) }
27
53
 
28
54
  before do
29
55
  FileUtils.mkdir_p template_root
@@ -31,22 +57,28 @@ describe Foreman::Export::Upstart do
31
57
  end
32
58
 
33
59
  it "can export with alternate template files" do
34
- upstart.export("/tmp/init", :template => template_root)
60
+ upstart.export
35
61
 
36
62
  File.read("/tmp/init/app.conf").should == "alternate_template\n"
37
63
  end
38
64
  end
39
65
 
40
66
  context "with alternate templates from home dir" do
41
- let(:default_template_root) {File.expand_path("~/.foreman/templates")}
67
+ let(:default_template_root) {File.expand_path("#{ENV['HOME']}/.foreman/templates")}
42
68
 
43
69
  before do
70
+ ENV['_FOREMAN_SPEC_HOME'] = ENV['HOME']
71
+ ENV['HOME'] = "/home/appuser"
44
72
  FileUtils.mkdir_p default_template_root
45
73
  File.open("#{default_template_root}/master.conf.erb", "w") { |f| f.puts "default_alternate_template" }
46
74
  end
47
75
 
76
+ after do
77
+ ENV['HOME'] = ENV.delete('_FOREMAN_SPEC_HOME')
78
+ end
79
+
48
80
  it "can export with alternate template files" do
49
- upstart.export("/tmp/init")
81
+ upstart.export
50
82
 
51
83
  File.read("/tmp/init/app.conf").should == "default_alternate_template\n"
52
84
  end
@@ -1,2 +1,24 @@
1
1
  require "spec_helper"
2
2
  require "foreman/export"
3
+
4
+ describe "Foreman::Export" do
5
+ subject { Foreman::Export }
6
+
7
+ describe "with a formatter that doesn't declare the appropriate class" do
8
+ it "prints an error" do
9
+ mock(subject).require("foreman/export/invalidformatter")
10
+ mock_export_error("Unknown export format: invalidformatter (no class Foreman::Export::Invalidformatter).") do
11
+ subject.formatter("invalidformatter")
12
+ end
13
+ end
14
+ end
15
+
16
+ describe "with an invalid formatter" do
17
+
18
+ it "prints an error" do
19
+ mock_export_error("Unknown export format: invalidformatter (unable to load file 'foreman/export/invalidformatter').") do
20
+ subject.formatter("invalidformatter")
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,26 @@
1
+ require "spec_helper"
2
+ require "foreman/helpers"
3
+
4
+ describe "Foreman::Helpers" do
5
+ before do
6
+ module Foo
7
+ class Bar; end
8
+ end
9
+ end
10
+
11
+ after do
12
+ Object.send(:remove_const, :Foo)
13
+ end
14
+
15
+ subject { o = Object.new; o.extend(Foreman::Helpers); o }
16
+
17
+ it "should classify words" do
18
+ subject.classify("foo").should == "Foo"
19
+ subject.classify("foo-bar").should == "FooBar"
20
+ end
21
+
22
+ it "should constantize words" do
23
+ subject.constantize("Object").should == Object
24
+ subject.constantize("Foo::Bar").should == Foo::Bar
25
+ end
26
+ end