locomotive_plugins 1.0.0.beta7 → 1.0.0.beta8
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/README.md
CHANGED
|
@@ -283,10 +283,16 @@ single site, since each site will have its own database.
|
|
|
283
283
|
### Rack App
|
|
284
284
|
|
|
285
285
|
Plugins can supply a Rack Application to be used for request handling. Do so by
|
|
286
|
-
overriding the `rack_app` class method on the plugin class. The
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
`
|
|
286
|
+
overriding the `rack_app` class method on the plugin class. The Rack app will
|
|
287
|
+
be given some helper methods:
|
|
288
|
+
|
|
289
|
+
* `plugin_object`: retrieve the plugin object.
|
|
290
|
+
* `full_path(path)`: generate the full url path for `path`. The `path` variable
|
|
291
|
+
is a url path relative to the mountpoint of the Rack app.
|
|
292
|
+
* `full_url(path)`: generate the full url for `path`. The `path` variable is a
|
|
293
|
+
url path relative to the mountpoint of the Rack app.
|
|
294
|
+
|
|
295
|
+
The `full_path` and `full_url` helpers may be used by the Rack app to generate
|
|
296
|
+
full paths and urls without explicit knowledge of the Rack app's mountpoint.
|
|
297
|
+
This is important since Locomotive will mount the app to a path based on its
|
|
298
|
+
`plugin_id`.
|
data/lib/locomotive/plugin.rb
CHANGED
|
@@ -5,86 +5,97 @@ module Locomotive
|
|
|
5
5
|
# `rack_app` method.
|
|
6
6
|
module RackAppHelpers
|
|
7
7
|
|
|
8
|
-
#
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
# @param base the class which includes this module
|
|
13
|
-
def self.included(base)
|
|
14
|
-
base.extend(ClassMethods)
|
|
15
|
-
end
|
|
8
|
+
# Helper methods to be added to the Rack application.
|
|
9
|
+
module HelperMethods
|
|
10
|
+
attr_accessor :plugin_object
|
|
11
|
+
attr_reader :env
|
|
16
12
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
#
|
|
13
|
+
# Set the env on the Rack app so that it can be retrieved later. This
|
|
14
|
+
# method will yield, and then set the env back to what it was after the
|
|
15
|
+
# block returns.
|
|
20
16
|
#
|
|
21
|
-
# @param
|
|
22
|
-
def
|
|
23
|
-
|
|
17
|
+
# @param env the Rack environment
|
|
18
|
+
def with_env(env)
|
|
19
|
+
old_env = @env
|
|
20
|
+
@env = env
|
|
21
|
+
yield
|
|
22
|
+
ensure
|
|
23
|
+
@env = old_env
|
|
24
24
|
end
|
|
25
|
-
end
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
# paths and URLs.
|
|
30
|
-
module RackAppHelpersClassMethods
|
|
31
|
-
# Set the full URL mountpoint for the Rack app. This will be set by
|
|
32
|
-
# Locomotive CMS. The URL must be an HTTP or HTTPS url with no query
|
|
33
|
-
# parameters or hash fragments.
|
|
26
|
+
# Generate the full absolute path for the given path based on the
|
|
27
|
+
# mountpoint of this plugin's rack app.
|
|
34
28
|
#
|
|
35
|
-
# @param
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
29
|
+
# @param path [String] the path relative to the mountpoint of the rack
|
|
30
|
+
# app
|
|
31
|
+
# @return the absolute path
|
|
32
|
+
def full_path(path)
|
|
33
|
+
[
|
|
34
|
+
base_uri_object.path.sub(%r{/+$}, ''),
|
|
35
|
+
path.sub(%r{^/+}, '')
|
|
36
|
+
].join('/')
|
|
37
|
+
end
|
|
40
38
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
39
|
+
# Generate the full URL for the given path based on the mountpoint of
|
|
40
|
+
# this plugin's rack app.
|
|
41
|
+
#
|
|
42
|
+
# @param path [String] the path relative to the mountpoint of the rack
|
|
43
|
+
# app
|
|
44
|
+
# @return the URL
|
|
45
|
+
def full_url(path)
|
|
46
|
+
[
|
|
47
|
+
base_uri_object.to_s.sub(%r{/+$}, ''),
|
|
48
|
+
path.sub(%r{^/+}, '')
|
|
49
|
+
].join('/')
|
|
50
|
+
end
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
protected
|
|
53
|
+
|
|
54
|
+
def base_uri_object
|
|
55
|
+
request_uri = env['REQUEST_URI']
|
|
56
|
+
base_path = env['SCRIPT_NAME']
|
|
57
|
+
base_uri = request_uri.sub(/(#{base_path}).*$/, '\1')
|
|
58
|
+
URI(base_uri)
|
|
53
59
|
end
|
|
60
|
+
end
|
|
54
61
|
|
|
55
|
-
|
|
62
|
+
# Wrapper class around the Rack application returned by the plugin class.
|
|
63
|
+
# Acts as middleware to ensure some setup and teardown when the app is
|
|
64
|
+
# called.
|
|
65
|
+
class RackAppWrapper
|
|
66
|
+
# Initialize with the Rack application to wrap.
|
|
56
67
|
#
|
|
57
|
-
# @
|
|
58
|
-
def
|
|
59
|
-
@
|
|
68
|
+
# @param app the Rack application
|
|
69
|
+
def initialize(app)
|
|
70
|
+
@app = app
|
|
60
71
|
end
|
|
61
|
-
end
|
|
62
72
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
73
|
+
# Call the underlying Rack app with the given environment.
|
|
74
|
+
#
|
|
75
|
+
# @param env the Rack environment
|
|
76
|
+
def call(env)
|
|
77
|
+
@app.with_env(env) do
|
|
78
|
+
@app.call(env)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
71
81
|
end
|
|
72
82
|
|
|
73
|
-
#
|
|
74
|
-
#
|
|
83
|
+
# Adds helper methods to the Rack app and returns another Rack app which
|
|
84
|
+
# wraps it. This method gets the Rack application ready to be called by
|
|
85
|
+
# Locomotive. Locomotive CMS calls this method to get the Rack app rather
|
|
86
|
+
# than calling `rack_app` directly.
|
|
75
87
|
#
|
|
76
|
-
# @
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
def full_url(path)
|
|
80
|
-
[ mountpoint.to_s.sub(%r{/+$}, ''), path.sub(%r{^/+}, '') ].join('/')
|
|
81
|
-
end
|
|
88
|
+
# @return the Rack app with helper methods
|
|
89
|
+
def prepared_rack_app
|
|
90
|
+
app = self.class.rack_app
|
|
82
91
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
92
|
+
# Extend helper module if needed
|
|
93
|
+
unless app.singleton_class.included_modules.include?(HelperMethods)
|
|
94
|
+
app.extend(HelperMethods)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
app.plugin_object = self
|
|
98
|
+
RackAppWrapper.new(app)
|
|
88
99
|
end
|
|
89
100
|
|
|
90
101
|
end
|
data/lib/version.rb
CHANGED
|
@@ -5,60 +5,96 @@ module Locomotive
|
|
|
5
5
|
module Plugin
|
|
6
6
|
describe RackAppHelpers do
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
let(:config) { {} }
|
|
9
|
+
|
|
10
|
+
let(:plugin) { PluginWithRackApp.new(config) }
|
|
11
|
+
|
|
12
|
+
let(:prepared_app) { plugin.prepared_rack_app }
|
|
13
|
+
|
|
14
|
+
let(:original_app) { plugin.class.rack_app }
|
|
15
|
+
|
|
16
|
+
it 'should add the plugin object to the Rack app' do
|
|
17
|
+
stub_app_call do
|
|
18
|
+
original_app.plugin_object.should == plugin
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
prepared_app.call(default_env)
|
|
10
22
|
end
|
|
11
23
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
24
|
+
it 'should add the Rack environment to the Rack app' do
|
|
25
|
+
stub_app_call do
|
|
26
|
+
original_app.env.should == default_env
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
prepared_app.call(default_env)
|
|
15
30
|
end
|
|
16
31
|
|
|
17
|
-
it 'should
|
|
18
|
-
|
|
19
|
-
|
|
32
|
+
it 'should add path and url helpers to the Rack app' do
|
|
33
|
+
original_app.respond_to?(:full_path).should be_true
|
|
34
|
+
original_app.respond_to?(:full_url).should be_true
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'should not add the helper methods if they have already been added' do
|
|
38
|
+
NewRackAppClass = Class.new do
|
|
39
|
+
def method_missing(*args)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
plugin = PluginWithRackApp.new(config)
|
|
44
|
+
rack_app = NewRackAppClass.new
|
|
45
|
+
plugin.class.stubs(:rack_app).returns(rack_app)
|
|
46
|
+
|
|
47
|
+
rack_app.expects(:extend).with(HelperMethods)
|
|
48
|
+
app = plugin.prepared_rack_app
|
|
49
|
+
|
|
50
|
+
plugin = PluginWithRackApp.new(config)
|
|
51
|
+
rack_app = NewRackAppClass.new
|
|
52
|
+
plugin.class.stubs(:rack_app).returns(rack_app)
|
|
53
|
+
|
|
54
|
+
app = plugin.prepared_rack_app
|
|
55
|
+
rack_app.expects(:extend).with(HelperMethods).never
|
|
56
|
+
app = plugin.prepared_rack_app
|
|
20
57
|
end
|
|
21
58
|
|
|
22
|
-
it 'should supply
|
|
23
|
-
|
|
24
|
-
'
|
|
25
|
-
|
|
26
|
-
|
|
59
|
+
it 'should supply an absolute path' do
|
|
60
|
+
stub_app_call do
|
|
61
|
+
original_app.full_path('/plugin/path').should == '/my/path/plugin/path'
|
|
62
|
+
original_app.full_path('another//path').should == '/my/path/another//path'
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
prepared_app.call(default_env)
|
|
27
66
|
end
|
|
28
67
|
|
|
29
|
-
it 'should
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
'
|
|
34
|
-
|
|
35
|
-
'ftp://my.server.com',
|
|
36
|
-
'http://my.server.com/my/path?q=value',
|
|
37
|
-
'http://my.server.com/my/path#fragment',
|
|
38
|
-
'https://my.server.com/my/path?q=value',
|
|
39
|
-
'https://my.server.com/my/path#fragment'
|
|
40
|
-
]
|
|
41
|
-
|
|
42
|
-
good_mountpoints = [
|
|
43
|
-
'http://my.server.com/my/path',
|
|
44
|
-
'http://my.server.com:3000/my/path',
|
|
45
|
-
'https://my.server.com/my/path',
|
|
46
|
-
'https://my.server.com:3000/my/path'
|
|
47
|
-
]
|
|
48
|
-
|
|
49
|
-
bad_mountpoints.each do |mountpoint|
|
|
50
|
-
lambda do
|
|
51
|
-
PluginWithRackApp.set_mountpoint(mountpoint)
|
|
52
|
-
end.should raise_exception(Locomotive::Plugin::Error)
|
|
53
|
-
PluginWithRackApp.mountpoint.should == old_mountpoint
|
|
68
|
+
it 'should supply a full url' do
|
|
69
|
+
stub_app_call do
|
|
70
|
+
original_app.full_url('/plugin/path').should ==
|
|
71
|
+
'http://www.example.com/my/path/plugin/path'
|
|
72
|
+
original_app.full_url('another//path').should ==
|
|
73
|
+
'http://www.example.com/my/path/another//path'
|
|
54
74
|
end
|
|
55
75
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
76
|
+
prepared_app.call(default_env)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
protected
|
|
80
|
+
|
|
81
|
+
def default_env
|
|
82
|
+
{
|
|
83
|
+
'REQUEST_URI' => 'http://www.example.com/my/path/request/path',
|
|
84
|
+
'SCRIPT_NAME' => '/my/path'
|
|
85
|
+
}
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Sets up an object which expects the method `the_block_has_been_called`
|
|
89
|
+
# to be invoked. This way, if you stub the app call but do not call
|
|
90
|
+
# `prepared_app.call`, the spec will fail.
|
|
91
|
+
def stub_app_call(&block)
|
|
92
|
+
obj = Object.new
|
|
93
|
+
original_app.block = Proc.new do
|
|
94
|
+
obj.the_block_has_been_called
|
|
95
|
+
block.call
|
|
61
96
|
end
|
|
97
|
+
obj.expects(:the_block_has_been_called).at_least_once
|
|
62
98
|
end
|
|
63
99
|
|
|
64
100
|
end
|
|
@@ -3,7 +3,16 @@ class PluginWithRackApp
|
|
|
3
3
|
include Locomotive::Plugin
|
|
4
4
|
|
|
5
5
|
def self.rack_app
|
|
6
|
-
|
|
6
|
+
RackApp
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class RackApp
|
|
10
|
+
class << self
|
|
11
|
+
attr_accessor :block
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.call(env)
|
|
15
|
+
block.call
|
|
7
16
|
[200, {'Content-Type' => 'text/html'}, []]
|
|
8
17
|
end
|
|
9
18
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: locomotive_plugins
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.0.
|
|
4
|
+
version: 1.0.0.beta8
|
|
5
5
|
prerelease: 6
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2013-01-
|
|
12
|
+
date: 2013-01-30 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: locomotive_liquid
|