monk 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +7 -1
- data/lib/monk.rb +44 -9
- data/monk.gemspec +4 -4
- data/test/commands.rb +61 -0
- data/test/integration_test.rb +107 -12
- data/test/monk_test.rb +127 -0
- metadata +6 -5
- data/test/sinatra_test.rb +0 -13
data/Rakefile
CHANGED
data/lib/monk.rb
CHANGED
@@ -6,25 +6,54 @@ class Monk < Thor
|
|
6
6
|
include Thor::Actions
|
7
7
|
|
8
8
|
desc "init", "Initialize a Monk application"
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
method_options(:source => :string)
|
10
|
+
def init(target = ".")
|
11
|
+
clone(source(options[:source] || "default"), target) ?
|
12
|
+
cleanup(target) :
|
13
|
+
say_status(:error, clone_error(target))
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "show NAME", "Display the repository address for NAME"
|
17
|
+
def show(name)
|
18
|
+
say_status name, source(name) || "repository not found"
|
19
|
+
end
|
20
|
+
|
21
|
+
desc "list", "Lists the configured repositories"
|
22
|
+
def list
|
23
|
+
monk_config.keys.sort.each do |key|
|
24
|
+
show(key)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
desc "add NAME REPOSITORY", "Add the repository to the configuration file"
|
29
|
+
def add(name, repository)
|
30
|
+
monk_config[name] = repository
|
31
|
+
write_monk_config_file
|
32
|
+
end
|
33
|
+
|
34
|
+
desc "rm NAME", "Remove the repository from the configuration file"
|
35
|
+
def rm(name)
|
36
|
+
monk_config.delete(name)
|
37
|
+
write_monk_config_file
|
12
38
|
end
|
13
39
|
|
14
40
|
private
|
15
41
|
|
16
42
|
def clone(source, target)
|
17
|
-
|
18
|
-
|
43
|
+
if Dir["#{target}/*"].empty?
|
44
|
+
say_status :fetching, source
|
45
|
+
system "git clone -q --depth 1 #{source} #{target}"
|
46
|
+
$?.success?
|
47
|
+
end
|
19
48
|
end
|
20
49
|
|
21
50
|
def cleanup(target)
|
22
51
|
inside(target) { remove_file ".git" }
|
23
|
-
say_status :
|
52
|
+
say_status :initialized, target
|
24
53
|
end
|
25
54
|
|
26
|
-
def source
|
27
|
-
monk_config[
|
55
|
+
def source(name = "default")
|
56
|
+
monk_config[name]
|
28
57
|
end
|
29
58
|
|
30
59
|
def monk_config_file
|
@@ -39,8 +68,9 @@ private
|
|
39
68
|
end
|
40
69
|
|
41
70
|
def write_monk_config_file
|
71
|
+
remove_file monk_config_file
|
42
72
|
create_file monk_config_file do
|
43
|
-
config = { "default" => "git://github.com/monkrb/skeleton.git" }
|
73
|
+
config = @monk_config || { "default" => "git://github.com/monkrb/skeleton.git" }
|
44
74
|
config.to_yaml
|
45
75
|
end
|
46
76
|
end
|
@@ -48,4 +78,9 @@ private
|
|
48
78
|
def self.source_root
|
49
79
|
"."
|
50
80
|
end
|
81
|
+
|
82
|
+
def clone_error(target)
|
83
|
+
"Couldn't clone repository into target directory '#{target}'. " +
|
84
|
+
"You must have git installed and the target directory must be empty."
|
85
|
+
end
|
51
86
|
end
|
data/monk.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "monk"
|
3
|
-
s.version = "0.0.
|
3
|
+
s.version = "0.0.4"
|
4
4
|
s.summary = "Monk, the glue framework"
|
5
5
|
s.description = "Monk is a glue framework for web development. It means that instead of installing all the tools you need for your projects, you can rely on a git repository and a list of dependencies, and Monk will care of the rest. By default, it ships with a Sinatra application that includes Contest, Stories, Webrat, Ohm and some other niceties, along with a structure and helpful documentation to get your hands wet in no time."
|
6
6
|
s.authors = ["Damian Janowski", "Michel Martens"]
|
@@ -11,9 +11,9 @@ Gem::Specification.new do |s|
|
|
11
11
|
|
12
12
|
s.executables << "monk"
|
13
13
|
|
14
|
-
s.add_dependency("
|
15
|
-
s.add_dependency("dependencies", ">= 0.0.
|
14
|
+
s.add_dependency("thor", "~> 0.11")
|
15
|
+
s.add_dependency("dependencies", ">= 0.0.6")
|
16
16
|
s.requirements << "git"
|
17
17
|
|
18
|
-
s.files = ["LICENSE", "README.markdown", "Rakefile", "bin/monk", "lib/monk.rb", "monk.gemspec", "test/integration_test.rb", "test/
|
18
|
+
s.files = ["LICENSE", "README.markdown", "Rakefile", "bin/monk", "lib/monk.rb", "monk.gemspec", "test/commands.rb", "test/integration_test.rb", "test/monk_test.rb"]
|
19
19
|
end
|
data/test/commands.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require "open3"
|
2
|
+
require "socket"
|
3
|
+
|
4
|
+
module Test::Commands
|
5
|
+
def sh(cmd)
|
6
|
+
out, err = nil
|
7
|
+
|
8
|
+
Open3.popen3(cmd) do |_in, _out, _err|
|
9
|
+
out = _out.read
|
10
|
+
err = _err.read
|
11
|
+
end
|
12
|
+
|
13
|
+
[out, err]
|
14
|
+
end
|
15
|
+
|
16
|
+
def sh_bg(cmd)
|
17
|
+
silence_stream($stdout) do
|
18
|
+
silence_stream($stderr) do
|
19
|
+
(pid = fork) ? Process.detach(pid) : exec("#{cmd} 2>&1>/dev/null")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def listening?(host, port)
|
25
|
+
begin
|
26
|
+
socket = TCPSocket.new(host, port)
|
27
|
+
socket.close unless socket.nil?
|
28
|
+
true
|
29
|
+
rescue Errno::ECONNREFUSED,
|
30
|
+
Errno::EBADF, # Windows
|
31
|
+
Errno::EADDRNOTAVAIL # Windows
|
32
|
+
false
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def wait_for_service(host, port, timeout = 3)
|
37
|
+
start_time = Time.now
|
38
|
+
|
39
|
+
until listening?(host, port)
|
40
|
+
if timeout && (Time.now > (start_time + timeout))
|
41
|
+
raise SocketError.new("Socket #{host}:#{port} did not open within #{timeout} seconds")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
true
|
46
|
+
end
|
47
|
+
|
48
|
+
def suspects(port)
|
49
|
+
list = sh("lsof -i :#{port}").first.split("\n")[1..-1] || []
|
50
|
+
list.map {|s| s[/^.+? (\d+)/, 1] }
|
51
|
+
end
|
52
|
+
|
53
|
+
def silence_stream(stream)
|
54
|
+
old_stream = stream.dup
|
55
|
+
stream.reopen(RUBY_PLATFORM =~ /mswin/ ? 'NUL:' : '/dev/null')
|
56
|
+
stream.sync = true
|
57
|
+
yield
|
58
|
+
ensure
|
59
|
+
stream.reopen(old_stream)
|
60
|
+
end
|
61
|
+
end
|
data/test/integration_test.rb
CHANGED
@@ -1,29 +1,124 @@
|
|
1
1
|
require "rubygems"
|
2
2
|
require "contest"
|
3
|
-
require "
|
3
|
+
require "hpricot"
|
4
4
|
|
5
|
-
|
5
|
+
ROOT = File.expand_path(File.join(File.dirname(__FILE__), ".."))
|
6
|
+
|
7
|
+
$:.unshift ROOT
|
8
|
+
|
9
|
+
require "test/commands"
|
6
10
|
|
7
11
|
class TestMonk < Test::Unit::TestCase
|
8
|
-
|
9
|
-
|
10
|
-
|
12
|
+
include Test::Commands
|
13
|
+
|
14
|
+
def root(*args)
|
15
|
+
File.join(ROOT, *args)
|
16
|
+
end
|
17
|
+
|
18
|
+
def monk(args = nil)
|
19
|
+
sh("ruby -rubygems #{root "bin/monk"} #{args}")
|
20
|
+
end
|
21
|
+
|
22
|
+
context "monk init NAME" do
|
23
|
+
setup do
|
24
|
+
@ports_to_close = []
|
25
|
+
end
|
26
|
+
|
27
|
+
def assert_url(url)
|
28
|
+
assert_match /200 OK/, sh("curl -I 0.0.0.0:4567#{url}").first.split("\n").first
|
29
|
+
end
|
11
30
|
|
12
|
-
|
13
|
-
|
14
|
-
|
31
|
+
def try_server(cmd, port)
|
32
|
+
binary = cmd[/^(.+?)( |$)/, 1]
|
33
|
+
|
34
|
+
flunk "Can't find `#{binary}`." unless system("which #{binary} > /dev/null")
|
35
|
+
|
36
|
+
kill_suspects(port)
|
37
|
+
sh_bg(cmd)
|
38
|
+
|
39
|
+
# Mark the port for closing on teardown, just in case the build fails.
|
40
|
+
@ports_to_close << port if wait_for_service("0.0.0.0", port)
|
41
|
+
|
42
|
+
doc = Hpricot(sh("curl 0.0.0.0:#{port}").first)
|
43
|
+
|
44
|
+
assert_match /Hello, world/, doc.at("body").inner_text
|
45
|
+
|
46
|
+
# Make sure all referenced URLs in the layout respond correctly.
|
47
|
+
doc.search("//*[@href]").each do |node|
|
48
|
+
assert_url node.attributes["href"]
|
15
49
|
end
|
16
50
|
|
17
|
-
[
|
51
|
+
doc.search("//*[@src]").each do |node|
|
52
|
+
assert_url node.attributes["src"]
|
53
|
+
end
|
18
54
|
end
|
19
55
|
|
20
56
|
should "create a skeleton app with all tests passing" do
|
21
|
-
|
57
|
+
flunk "There is another server running on 0.0.0.0:4567. Suspect PIDs: #{suspects(4567).join(", ")}" if listening?("0.0.0.0", 4567)
|
58
|
+
flunk "There is another server running on 0.0.0.0:9292. Suspect PIDs: #{suspects(9292).join(", ")}" if listening?("0.0.0.0", 9292)
|
59
|
+
|
60
|
+
Dir.chdir(root("test", "tmp")) do
|
22
61
|
FileUtils.rm_rf("monk-test")
|
23
62
|
|
24
63
|
out, err = monk("init monk-test")
|
25
|
-
|
26
|
-
|
64
|
+
assert_match /initialized.* monk-test/, out
|
65
|
+
|
66
|
+
Dir.chdir("monk-test") do
|
67
|
+
assert !File.directory?(".git")
|
68
|
+
|
69
|
+
FileUtils.cp("config/settings.example.yml", "config/settings.yml")
|
70
|
+
FileUtils.cp("config/redis/development.example.conf", "config/redis/development.conf")
|
71
|
+
FileUtils.cp("config/redis/test.example.conf", "config/redis/test.conf")
|
72
|
+
|
73
|
+
# Load Redis.
|
74
|
+
sh "redis-server config/redis/test.conf"
|
75
|
+
wait_for_service("0.0.0.0", 6380)
|
76
|
+
|
77
|
+
sh "redis-server config/redis/development.conf"
|
78
|
+
wait_for_service("0.0.0.0", 6379)
|
79
|
+
|
80
|
+
assert sh("rake"), "the build didn't pass."
|
81
|
+
assert sh("rake1.9"), "the build didn't pass under Ruby 1.9."
|
82
|
+
|
83
|
+
try_server "ruby init.rb", 4567
|
84
|
+
try_reloading
|
85
|
+
try_server "rackup", 9292
|
86
|
+
|
87
|
+
try_server "ruby1.9 init.rb", 4567
|
88
|
+
try_reloading
|
89
|
+
try_server "rackup1.9", 9292
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def try_reloading
|
95
|
+
gsub_file("app/routes/home.rb", "haml :home", "'Goodbye'") do
|
96
|
+
sleep 0.2
|
97
|
+
assert_match /Goodbye/, sh("curl 0.0.0.0:4567").first
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def gsub_file(file, *args)
|
102
|
+
old = File.read(file)
|
103
|
+
|
104
|
+
begin
|
105
|
+
new = old.gsub(*args)
|
106
|
+
File.open(file, "w") {|f| f.write(new) }
|
107
|
+
yield
|
108
|
+
ensure
|
109
|
+
File.open(file, "w") {|f| f.write(old) }
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def kill_suspects(port)
|
114
|
+
list = suspects(port)
|
115
|
+
|
116
|
+
sh "kill -9 #{list.join(" ")}" unless list.empty?
|
117
|
+
end
|
118
|
+
|
119
|
+
teardown do
|
120
|
+
@ports_to_close.each do |port|
|
121
|
+
kill_suspects port
|
27
122
|
end
|
28
123
|
end
|
29
124
|
end
|
data/test/monk_test.rb
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "contest"
|
3
|
+
require "hpricot"
|
4
|
+
|
5
|
+
ROOT = File.expand_path(File.join(File.dirname(__FILE__), ".."))
|
6
|
+
|
7
|
+
$:.unshift ROOT
|
8
|
+
|
9
|
+
require "test/commands"
|
10
|
+
|
11
|
+
class TestMonk < Test::Unit::TestCase
|
12
|
+
include Test::Commands
|
13
|
+
|
14
|
+
def root(*args)
|
15
|
+
File.join(ROOT, *args)
|
16
|
+
end
|
17
|
+
|
18
|
+
def monk(args = nil)
|
19
|
+
sh("ruby -rubygems #{root "bin/monk"} #{args}")
|
20
|
+
end
|
21
|
+
|
22
|
+
context "monk init NAME" do
|
23
|
+
should "fail if the target working directory is not empty" do
|
24
|
+
Dir.chdir(root("test", "tmp")) do
|
25
|
+
FileUtils.rm_rf("monk-test")
|
26
|
+
FileUtils.mkdir("monk-test")
|
27
|
+
|
28
|
+
Dir.chdir("monk-test") do
|
29
|
+
FileUtils.touch("foobar")
|
30
|
+
end
|
31
|
+
|
32
|
+
out, err = monk("init monk-test")
|
33
|
+
assert_match /error/, out
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
should "create a skeleton app in the target directory" do
|
38
|
+
Dir.chdir(root("test", "tmp")) do
|
39
|
+
FileUtils.rm_rf("monk-test")
|
40
|
+
|
41
|
+
out, err = monk("init monk-test")
|
42
|
+
assert_match /initialized.* monk-test/, out
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "monk init" do
|
48
|
+
should "fail if the current working directory is not empty" do
|
49
|
+
Dir.chdir(root("test", "tmp")) do
|
50
|
+
FileUtils.rm_rf("monk-test")
|
51
|
+
FileUtils.mkdir("monk-test")
|
52
|
+
|
53
|
+
|
54
|
+
Dir.chdir("monk-test") do
|
55
|
+
FileUtils.touch("foobar")
|
56
|
+
out, err = monk("init")
|
57
|
+
assert_match /error/, out
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
should "create a skeleton app in the working directory" do
|
63
|
+
Dir.chdir(root("test", "tmp")) do
|
64
|
+
FileUtils.rm_rf("monk-test")
|
65
|
+
FileUtils.mkdir("monk-test")
|
66
|
+
|
67
|
+
Dir.chdir("monk-test") do
|
68
|
+
out, err = monk("init")
|
69
|
+
assert_match /initialized/, out
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
should "use an alternative skeleton if the option is provided" do
|
75
|
+
Dir.chdir(root("test", "tmp")) do
|
76
|
+
FileUtils.rm_rf("monk-test")
|
77
|
+
FileUtils.mkdir("monk-test")
|
78
|
+
|
79
|
+
monk("add foobar git://github.com/monkrb/skeleton.git")
|
80
|
+
|
81
|
+
Dir.chdir("monk-test") do
|
82
|
+
out, err = monk("init -s foo")
|
83
|
+
assert_match /initialized/, out
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context "monk show NAME" do
|
90
|
+
should "display the repository for NAME" do
|
91
|
+
out, err = monk("show default")
|
92
|
+
assert out["git://github.com/monkrb/skeleton.git"]
|
93
|
+
end
|
94
|
+
|
95
|
+
should "display nothing if NAME is not set" do
|
96
|
+
out, err = monk("show foobar")
|
97
|
+
assert out["repository not found"]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context "monk list" do
|
102
|
+
should "display the configured repositories" do
|
103
|
+
out, err = monk("list")
|
104
|
+
assert out["default"]
|
105
|
+
assert out["git://github.com/monkrb/skeleton.git"]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context "monk add NAME REPOSITORY" do
|
110
|
+
should "add the named repository to the configuration" do
|
111
|
+
monk("add foobar git://github.com/monkrb/foo.git")
|
112
|
+
out, err = monk("show foobar")
|
113
|
+
assert out["foobar"]
|
114
|
+
assert out["git://github.com/monkrb/foo.git"]
|
115
|
+
monk("rm foobar")
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context "monk rm NAME" do
|
120
|
+
should "remove the named repository from the configuration" do
|
121
|
+
monk("add foobar git://github.com/monkrb/foo.git")
|
122
|
+
monk("rm foobar")
|
123
|
+
out, err = monk("show foobar")
|
124
|
+
assert out["repository not found"]
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: monk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Damian Janowski
|
@@ -10,11 +10,11 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2009-07
|
13
|
+
date: 2009-08-07 00:00:00 -03:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
|
-
name:
|
17
|
+
name: thor
|
18
18
|
type: :runtime
|
19
19
|
version_requirement:
|
20
20
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -31,7 +31,7 @@ dependencies:
|
|
31
31
|
requirements:
|
32
32
|
- - ">="
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version: 0.0.
|
34
|
+
version: 0.0.6
|
35
35
|
version:
|
36
36
|
description: Monk is a glue framework for web development. It means that instead of installing all the tools you need for your projects, you can rely on a git repository and a list of dependencies, and Monk will care of the rest. By default, it ships with a Sinatra application that includes Contest, Stories, Webrat, Ohm and some other niceties, along with a structure and helpful documentation to get your hands wet in no time.
|
37
37
|
email:
|
@@ -50,8 +50,9 @@ files:
|
|
50
50
|
- bin/monk
|
51
51
|
- lib/monk.rb
|
52
52
|
- monk.gemspec
|
53
|
+
- test/commands.rb
|
53
54
|
- test/integration_test.rb
|
54
|
-
- test/
|
55
|
+
- test/monk_test.rb
|
55
56
|
has_rdoc: true
|
56
57
|
homepage: http://monkrb.com
|
57
58
|
licenses: []
|
data/test/sinatra_test.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/helper'
|
2
|
-
|
3
|
-
class SinatraTest < Test::Unit::TestCase
|
4
|
-
it 'creates a new Sinatra::Base subclass on new' do
|
5
|
-
app =
|
6
|
-
Sinatra.new do
|
7
|
-
get '/' do
|
8
|
-
'Hello World'
|
9
|
-
end
|
10
|
-
end
|
11
|
-
assert_same Sinatra::Base, app.superclass
|
12
|
-
end
|
13
|
-
end
|