monk 0.0.3 → 0.0.4
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/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
|