pakada 0.0.0 → 0.0.1
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/.rspec +1 -0
- data/Gemfile +2 -9
- data/Rakefile +7 -2
- data/lib/pakada/module.rb +41 -57
- data/lib/pakada/version.rb +1 -1
- data/lib/pakada.rb +80 -96
- data/pakada.gemspec +27 -0
- data/spec/module_spec.rb +180 -0
- data/spec/pakada_spec.rb +272 -0
- data/spec/spec_helper.rb +15 -0
- metadata +53 -61
- data/README.rdoc +0 -1
- data/lib/pakada/application.rb +0 -23
- data/lib/pakada/boot.rb +0 -7
- data/lib/pakada/support/aliasing.rb +0 -8
- data/lib/pakada/support/inflection.rb +0 -35
- data/lib/pakada/support/instance_exec.rb +0 -27
- data/lib/pakada/support.rb +0 -9
- data/lib/pakada/tasks.rb +0 -22
- data/lib/pakada/test.rb +0 -14
- data/lib/pakada/test_case.rb +0 -69
- data/tasks/test.rb +0 -73
- data/test/files.rb +0 -60
- data/test/helper.rb +0 -1
- data/test/module_test.rb +0 -81
- data/test/pakada_test.rb +0 -80
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
data/lib/pakada/module.rb
CHANGED
@@ -1,81 +1,65 @@
|
|
1
1
|
class Pakada
|
2
2
|
module Module
|
3
|
-
@descendants =
|
3
|
+
@descendants = {}
|
4
4
|
|
5
5
|
class << self
|
6
6
|
attr_reader :descendants
|
7
7
|
|
8
|
-
def
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
i = $LOAD_PATH.find_index(spec.load_paths.first)
|
13
|
-
specs[i] = spec
|
14
|
-
end
|
15
|
-
specs.delete(nil)
|
8
|
+
def included(klass)
|
9
|
+
klass.send :include, Hooked::Container
|
10
|
+
|
11
|
+
klass.singleton_class.class_eval { attr_reader :module_name, :path }
|
16
12
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
:path => spec.full_gem_path,
|
23
|
-
} unless @descendants[name]
|
13
|
+
unless klass.module_name
|
14
|
+
klass.instance_variable_set :@module_name, detect_name(klass.to_s)
|
15
|
+
end
|
16
|
+
unless klass.module_name
|
17
|
+
raise "Could not detect name for module #{klass}"
|
24
18
|
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def load
|
28
|
-
prepare
|
29
19
|
|
30
|
-
|
31
|
-
|
32
|
-
|
20
|
+
unless klass.path
|
21
|
+
# use Kernel.caller instead of self.caller so Mocha doesn't explode...
|
22
|
+
file = Kernel.caller[0].split(":")[0]
|
23
|
+
klass.instance_variable_set :@path, detect_path(file)
|
33
24
|
end
|
25
|
+
|
26
|
+
@descendants[klass.module_name] = klass
|
34
27
|
end
|
35
28
|
|
36
|
-
def
|
37
|
-
|
29
|
+
def detect_name(klass)
|
30
|
+
name = klass.gsub(/^Pakada::/, "").
|
31
|
+
gsub(/([A-Z]+)([A-Z][a-z])/, "\\1_\\2").
|
32
|
+
gsub(/([a-z])([A-Z])/, "\\1_\\2").
|
33
|
+
gsub(/::/, "_").
|
34
|
+
downcase
|
35
|
+
return name.to_sym if name.match /^[a-z0-9_]+$/
|
38
36
|
end
|
39
37
|
|
40
|
-
def
|
41
|
-
|
42
|
-
|
38
|
+
def detect_path(file)
|
39
|
+
filepath = nil
|
40
|
+
filepath = file if file =~ /^\// && File.exists?(file)
|
41
|
+
$LOAD_PATH.each do |dir|
|
42
|
+
x = File.join dir, file
|
43
|
+
if File.exists? x
|
44
|
+
filepath = File.expand_path x
|
45
|
+
break
|
46
|
+
end
|
47
|
+
end unless filepath
|
48
|
+
return unless filepath
|
43
49
|
|
44
|
-
|
45
|
-
|
50
|
+
segments = File.dirname(filepath).split("/").reverse
|
51
|
+
pos = segments.find_index("lib") || -1
|
52
|
+
|
53
|
+
segments[(pos + 1)..-1].reverse.join "/"
|
46
54
|
end
|
47
55
|
end
|
48
56
|
|
49
|
-
def
|
50
|
-
|
51
|
-
hooks[name].each {|h| instance_exec(*args, &h) } if hooks[name]
|
52
|
-
end
|
53
|
-
|
54
|
-
def version
|
55
|
-
return self.class.version
|
57
|
+
def module_name
|
58
|
+
self.class.module_name
|
56
59
|
end
|
57
60
|
|
58
61
|
def path
|
59
|
-
|
60
|
-
end
|
61
|
-
|
62
|
-
module ClassMethods
|
63
|
-
def hook(name, &block)
|
64
|
-
@hooks[name] ||= []
|
65
|
-
@hooks[name] << block
|
66
|
-
end
|
67
|
-
|
68
|
-
def name
|
69
|
-
return @name ||= Pakada::Module.descendants.find {|m| m[1][:klass] == self }[0]
|
70
|
-
end
|
71
|
-
|
72
|
-
def version
|
73
|
-
return Pakada::Module.descendants[name][:gemspec].version.to_s
|
74
|
-
end
|
75
|
-
|
76
|
-
def path
|
77
|
-
return Pakada::Module.descendants[name][:path]
|
78
|
-
end
|
62
|
+
self.class.path
|
79
63
|
end
|
80
64
|
end
|
81
65
|
end
|
data/lib/pakada/version.rb
CHANGED
data/lib/pakada.rb
CHANGED
@@ -1,113 +1,97 @@
|
|
1
1
|
require "rack"
|
2
|
-
require "
|
2
|
+
require "hooked"
|
3
3
|
|
4
|
-
require "pakada/application"
|
5
4
|
require "pakada/module"
|
6
5
|
require "pakada/version"
|
7
6
|
|
8
7
|
class Pakada
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
@modules = Dictionary.new
|
39
|
-
@hooks = {}
|
40
|
-
Module.descendants.each do |name, mod|
|
41
|
-
@modules[name] = mod[:klass].new
|
42
|
-
@modules[name].hook(:activate) unless testing?
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def [](name)
|
47
|
-
return modules[name]
|
48
|
-
end
|
49
|
-
|
50
|
-
def []=(name, mod)
|
51
|
-
modules[name] = mod
|
52
|
-
end
|
53
|
-
|
54
|
-
def hook(name, *args)
|
55
|
-
catch(:halt) { @modules.each_value {|mod| mod.hook(name, *args) } }
|
56
|
-
end
|
57
|
-
|
58
|
-
def hook_reverse(name, *args)
|
59
|
-
catch(:halt) { @modules.reverse.each_value {|mod| mod.hook(name, *args) } }
|
60
|
-
end
|
61
|
-
|
62
|
-
def app
|
63
|
-
unless @app
|
64
|
-
@middleware.run(Application)
|
65
|
-
@app = @middleware.to_app
|
66
|
-
end
|
67
|
-
return @app
|
68
|
-
end
|
69
|
-
|
70
|
-
def request
|
71
|
-
return Application.request
|
72
|
-
end
|
73
|
-
|
74
|
-
def response
|
75
|
-
return Application.response
|
76
|
-
end
|
77
|
-
|
78
|
-
def reset
|
79
|
-
@env = nil
|
80
|
-
@middleware = Rack::Builder.new
|
81
|
-
@modules = Dictionary.new
|
82
|
-
@app = nil
|
83
|
-
end
|
84
|
-
|
85
|
-
def shutdown
|
86
|
-
hook_reverse(:shutdown) unless testing?
|
87
|
-
|
88
|
-
reset
|
89
|
-
end
|
8
|
+
include Hooked::Container
|
9
|
+
|
10
|
+
DEFAULT_APP = proc do |req_env|
|
11
|
+
Rack::Response.new("Hi, I'm Pakada #{VERSION}").finish
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :env, :modules, :hooks, :middleware
|
15
|
+
attr_accessor :app
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@middleware = []
|
19
|
+
end
|
20
|
+
|
21
|
+
def development?
|
22
|
+
env == :development
|
23
|
+
end
|
24
|
+
|
25
|
+
def testing?
|
26
|
+
env == :testing
|
27
|
+
end
|
28
|
+
|
29
|
+
def production?
|
30
|
+
env == :production
|
31
|
+
end
|
32
|
+
|
33
|
+
def boot
|
34
|
+
load_env
|
35
|
+
load_modules
|
36
|
+
load_hooks
|
90
37
|
|
91
|
-
|
92
|
-
|
38
|
+
hooks.invoke(:boot) unless testing?
|
39
|
+
end
|
40
|
+
|
41
|
+
def load_env
|
42
|
+
@env = (ENV["RACK_ENV"] || :development).to_sym
|
43
|
+
end
|
44
|
+
|
45
|
+
def load_modules
|
46
|
+
@modules = Pakada::Module.descendants.values.inject({}) do |h, m|
|
47
|
+
h[m.module_name] = m.new; h
|
93
48
|
end
|
94
|
-
|
95
|
-
|
96
|
-
|
49
|
+
end
|
50
|
+
|
51
|
+
def load_hooks
|
52
|
+
raise "modules have not been loaded" unless modules.respond_to? :values
|
53
|
+
@hooks = Hooked::Controller.new self, *modules.values
|
54
|
+
end
|
55
|
+
|
56
|
+
def call(req_env)
|
57
|
+
to_app.call(req_env)
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_app
|
61
|
+
builder = Rack::Builder.new
|
62
|
+
middleware.each {|mw| builder.use *(Array === mw ? mw : [mw]) }
|
63
|
+
builder.run proc {|req_env| handle_request(req_env) }
|
64
|
+
builder
|
65
|
+
end
|
66
|
+
|
67
|
+
def handle_request(req_env)
|
68
|
+
req = Rack::Request.new req_env
|
69
|
+
hooks.invoke(:request, req).finish
|
70
|
+
end
|
71
|
+
|
72
|
+
hookable :boot do |nothing|; end
|
73
|
+
|
74
|
+
hookable :request do |ctx|
|
75
|
+
resp = (app || DEFAULT_APP).call ctx.args.env
|
76
|
+
ctx.result = Rack::Response.new resp[2], *resp[0..1]
|
77
|
+
end
|
78
|
+
|
79
|
+
class << self
|
80
|
+
def instance
|
81
|
+
@instance ||= new
|
97
82
|
end
|
98
83
|
|
99
|
-
def
|
100
|
-
|
84
|
+
def reset_instance
|
85
|
+
@instance = nil
|
101
86
|
end
|
102
87
|
|
103
|
-
def
|
104
|
-
|
88
|
+
def method_missing(m, *args, &block)
|
89
|
+
super(m, *args, &block) unless instance.respond_to? m
|
90
|
+
instance.send m, *args, &block
|
105
91
|
end
|
106
92
|
|
107
|
-
def
|
108
|
-
|
93
|
+
def respond_to?(m)
|
94
|
+
super(m) || instance.respond_to?(m)
|
109
95
|
end
|
110
96
|
end
|
111
|
-
|
112
|
-
reset
|
113
97
|
end
|
data/pakada.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "pakada/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "pakada"
|
7
|
+
s.version = Pakada::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Lars Gierth"]
|
10
|
+
s.email = ["lars.gierth@gmail.com"]
|
11
|
+
s.homepage = "http://rubygems.org/gems/pakada"
|
12
|
+
s.summary = %q{Very Extensible HTTP Container For Ruby}
|
13
|
+
#s.description = %q{TODO: Write a gem description}
|
14
|
+
|
15
|
+
s.add_dependency "rack", "~> 1.2.1"
|
16
|
+
s.add_dependency "hooked", "~> 0.1.0"
|
17
|
+
|
18
|
+
s.add_development_dependency "rspec", "~> 2.3"
|
19
|
+
s.add_development_dependency "mocha", "~> 0.9.10"
|
20
|
+
s.add_development_dependency "fakefs", "~> 0.3.1"
|
21
|
+
s.add_development_dependency "fakefs-require", "~> 0.2.1"
|
22
|
+
|
23
|
+
s.files = `git ls-files`.split("\n") - [".gitignore", ".rvmrc", "config.ru"]
|
24
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
25
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
26
|
+
s.require_paths = ["lib"]
|
27
|
+
end
|
data/spec/module_spec.rb
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
describe Pakada::Module do
|
6
|
+
describe ".descendants" do
|
7
|
+
it "keeps a list containing its descendants" do
|
8
|
+
Pakada::Module.descendants.should == {}
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe ".detect_path" do
|
13
|
+
before :each do
|
14
|
+
FakeFS.activate!
|
15
|
+
FakeFS::Require.activate! :fallback => true
|
16
|
+
end
|
17
|
+
|
18
|
+
after :each do
|
19
|
+
FakeFS::Require.deactivate!
|
20
|
+
FakeFS.deactivate!
|
21
|
+
FakeFS::FileSystem.clear
|
22
|
+
end
|
23
|
+
|
24
|
+
it "loops through the load path to find a matching path" do
|
25
|
+
m = Pakada::Module
|
26
|
+
|
27
|
+
path = "/my/path"
|
28
|
+
FileUtils.mkdir_p path + "/lib"
|
29
|
+
FileUtils.touch path + "/lib/some_module.rb"
|
30
|
+
$LOAD_PATH << path + "/lib"
|
31
|
+
|
32
|
+
m.detect_path("some_module.rb").should == path
|
33
|
+
m.detect_path(path + "/lib/some_module.rb").should == path
|
34
|
+
$LOAD_PATH.delete path + "/lib"
|
35
|
+
|
36
|
+
m.detect_path("config.ru").should be_nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe ".detect_name" do
|
41
|
+
it "strips off Pakada:: and normalizes the klass name" do
|
42
|
+
m = Pakada::Module
|
43
|
+
|
44
|
+
m.detect_name("Pakada::SomeModule::FOO").should == :some_module_foo
|
45
|
+
m.detect_name("My_Module").should == :my_module
|
46
|
+
|
47
|
+
m.detect_name("L337").should == :l337
|
48
|
+
m.detect_name("Läö7").should be_nil
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe ".included hook" do
|
53
|
+
before :each do
|
54
|
+
FakeFS.activate!
|
55
|
+
FakeFS::Require.activate! :fallback => true
|
56
|
+
end
|
57
|
+
|
58
|
+
after :each do
|
59
|
+
Pakada::Module.descendants.clear
|
60
|
+
|
61
|
+
FakeFS::Require.deactivate!
|
62
|
+
FakeFS.deactivate!
|
63
|
+
FakeFS::FileSystem.clear
|
64
|
+
end
|
65
|
+
|
66
|
+
it "tries to determine the module's name" do
|
67
|
+
klass = Class.new
|
68
|
+
Pakada::Module.should_receive(:detect_name).with(klass.to_s).once { :some_module }
|
69
|
+
klass.send(:include, Pakada::Module)
|
70
|
+
klass.module_name.should == :some_module
|
71
|
+
end
|
72
|
+
|
73
|
+
it "crashes if it can't detect a name" do
|
74
|
+
klass = Class.new
|
75
|
+
Pakada::Module.should_receive(:detect_name).with(klass.to_s).once { nil }
|
76
|
+
proc { klass.send(:include, Pakada::Module) }.should raise_error(RuntimeError)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "respects an already set name" do
|
80
|
+
Pakada::Module.should_not_receive(:detect_name)
|
81
|
+
klass = Class.new do
|
82
|
+
@module_name = :some_module
|
83
|
+
include Pakada::Module
|
84
|
+
end
|
85
|
+
klass.module_name.should == :some_module
|
86
|
+
end
|
87
|
+
|
88
|
+
it "tries to determine the module's path" do
|
89
|
+
path = "/my/path"
|
90
|
+
file = path + "/lib/some_module.rb"
|
91
|
+
|
92
|
+
Kernel.should_receive(:mock_caller).once { [file + ":1: in `something'"] }
|
93
|
+
Kernel.instance_eval do
|
94
|
+
alias orig_caller caller
|
95
|
+
alias caller mock_caller
|
96
|
+
end
|
97
|
+
|
98
|
+
Pakada::Module.should_receive(:detect_path).with(file).once { path }
|
99
|
+
klass = Class.new do
|
100
|
+
@module_name = :some_module
|
101
|
+
include Pakada::Module
|
102
|
+
end
|
103
|
+
klass.path.should == path
|
104
|
+
|
105
|
+
Kernel.instance_eval { alias caller orig_caller }
|
106
|
+
end
|
107
|
+
|
108
|
+
it "respects an already set path" do
|
109
|
+
Pakada::Module.should_not_receive(:detect_path)
|
110
|
+
klass = Class.new do
|
111
|
+
@module_name = :some_module
|
112
|
+
@path = "/my/path"
|
113
|
+
include Pakada::Module
|
114
|
+
end
|
115
|
+
klass.path.should == "/my/path"
|
116
|
+
end
|
117
|
+
|
118
|
+
it "adds the module to the list of descendants" do
|
119
|
+
klass = Class.new do
|
120
|
+
@module_name = :some_module
|
121
|
+
include Pakada::Module
|
122
|
+
end
|
123
|
+
Pakada::Module.descendants[:some_module].should == klass
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe "SomeModule" do
|
129
|
+
before :each do
|
130
|
+
@klass = Class.new do
|
131
|
+
@module_name = :foo
|
132
|
+
@path = "/opt/pakada"
|
133
|
+
include Pakada::Module
|
134
|
+
end
|
135
|
+
@obj = @klass.new
|
136
|
+
end
|
137
|
+
|
138
|
+
after :each do
|
139
|
+
@klass, @obj = nil
|
140
|
+
Pakada::Module.descendants.clear
|
141
|
+
end
|
142
|
+
|
143
|
+
it "is a hooking container" do
|
144
|
+
@obj.should respond_to(:hooked)
|
145
|
+
@obj.should respond_to(:hooked=)
|
146
|
+
@obj.should respond_to(:hookable)
|
147
|
+
end
|
148
|
+
|
149
|
+
describe ".module_name" do
|
150
|
+
it "contains the module's name" do
|
151
|
+
@klass.module_name.should == :foo
|
152
|
+
end
|
153
|
+
|
154
|
+
it "is read-only" do
|
155
|
+
proc { @klass.module_name = :bar }.should raise_error(NoMethodError)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe ".path" do
|
160
|
+
it "contains the module's base path" do
|
161
|
+
@klass.path.should == "/opt/pakada"
|
162
|
+
end
|
163
|
+
|
164
|
+
it "is read-only" do
|
165
|
+
proc { @klass.path = "/tmp/pkd" }.should raise_error(NoMethodError)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
describe "#module_name" do
|
170
|
+
it "is a shortcut for ::module_name" do
|
171
|
+
@obj.module_name.should == @klass.module_name
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
describe "#path" do
|
176
|
+
it "is a shortcut for ::path" do
|
177
|
+
@obj.path.should == @klass.path
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|