locomotive_plugins 1.0.0.beta4 → 1.0.0.beta5

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.
@@ -0,0 +1,47 @@
1
+
2
+ module Locomotive
3
+ module Plugin
4
+ module Liquid
5
+ # @api internal
6
+ #
7
+ # Adds the plugin object to the liquid context.
8
+ module ContextHelpers
9
+
10
+ # Adds the plugin object to the liquid context object to be used by
11
+ # tags, filters, and drops. This method looks in the +:site+ register
12
+ # for an object which responds to +#plugin_object_for_id+ in order to
13
+ # populate the +:plugin_object+ register. If such an object does not
14
+ # exist, the method simply yields without altering the context object.
15
+ # Otherwise, after yielding, the context object is reset to its
16
+ # previous state.
17
+ #
18
+ # @param plugin_id [String] the plugin id to use
19
+ # @param context [Liquid::Context] the liquid context object
20
+ def self.add_plugin_object_to_context(plugin_id, context)
21
+ site = self.fetch_site(context)
22
+ if site
23
+ old = context.registers[:plugin_object]
24
+ obj = site.plugin_object_for_id(plugin_id)
25
+ context.registers[:plugin_object] = obj
26
+ yield
27
+ context.registers[:plugin_object] = old
28
+ else
29
+ yield
30
+ end
31
+ end
32
+
33
+ protected
34
+
35
+ # Fetch the site from the context assuming it exists and responds to
36
+ # the +#plugin_object_for_id+ method.
37
+ #
38
+ # @param context [Liquid::Context] the liquid context object
39
+ # @return the site object or +nil+
40
+ def self.fetch_site(context)
41
+ site = context.registers[:site]
42
+ site if site.respond_to?(:plugin_object_for_id)
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,36 @@
1
+
2
+ module Locomotive
3
+ module Plugin
4
+ module Liquid
5
+ # @api internal
6
+ #
7
+ # Extension to liquid drops added by plugins.
8
+ module DropExtension
9
+
10
+ # Allow setting the plugin_id, but only once.
11
+ def set_plugin_id(plugin_id)
12
+ @_plugin_id ||= plugin_id
13
+ end
14
+
15
+ # Add the plugin object to the context when invoked (see
16
+ # Liquid::Drop#invoke_drop)
17
+ def invoke_drop(method)
18
+ value = nil
19
+
20
+ ContextHelpers.add_plugin_object_to_context(_plugin_id, @context) do
21
+ value = super
22
+ end
23
+
24
+ value
25
+ end
26
+ alias :[] :invoke_drop
27
+
28
+ private
29
+
30
+ # Plugin ID (see set_plugin_id).
31
+ attr_reader :_plugin_id
32
+
33
+ end
34
+ end
35
+ end
36
+ end
@@ -2,19 +2,19 @@
2
2
  module Locomotive
3
3
  module Plugin
4
4
  module Liquid
5
- # @private
5
+ # @api internal
6
+ #
6
7
  # This module provides functionality for the module which aggregates all
7
8
  # the prefixed filter methods. See
8
- # <tt>Locomotive::Plugin::Liquid#prefixed_liquid_filter_module</tt>
9
+ # <tt>Locomotive::Plugin::Liquid#prefixed_liquid_filter_module</tt>.
9
10
  module PrefixedFilterModule
10
11
 
11
12
  protected
12
13
 
13
- # This method is overridden by LocomotiveCMS to provide custom
14
- # functionality when a prefixed method is called
15
- def filter_method_called(prefix, meth)
16
- end
17
-
14
+ # Build the object to use for passing through the non-prefixed methods.
15
+ #
16
+ # @param modules_to_extend [Array] the module for the passthrough object
17
+ # to extend
18
18
  def _build_passthrough_object(modules_to_extend)
19
19
  obj = ::Liquid::Strainer.new(@context)
20
20
 
@@ -25,6 +25,10 @@ module Locomotive
25
25
  obj
26
26
  end
27
27
 
28
+ # Get the passthrough object for the given prefix.
29
+ #
30
+ # @param prefix [String] the prefix to use
31
+ # @return the passthrough object for +prefix+
28
32
  def _passthrough_object(prefix)
29
33
  @_passthrough_objects ||= {}
30
34
  obj = @_passthrough_objects[prefix]
@@ -43,18 +47,21 @@ module Locomotive
43
47
  @_passthrough_objects[prefix] = self._build_passthrough_object(modules)
44
48
  end
45
49
 
50
+ # Passthrough method call with the given prefix and input.
51
+ #
52
+ # @param prefix [String] the prefix to use
53
+ # @param meth [Symbol] the method to call
54
+ # @param input [String] the input to the method
55
+ # @return the result of calling the method on the passthrough object
46
56
  def _passthrough_filter_call(prefix, meth, input)
47
- p = Proc.new do
48
- self._passthrough_object(prefix).__send__(meth, input)
49
- end
57
+ # Setup context object and call the passthrough
58
+ output = nil
50
59
 
51
- # Call hook and grab return value if it yields
52
- ret = nil
53
- self.filter_method_called(prefix, meth) do
54
- ret = p.call
60
+ ContextHelpers.add_plugin_object_to_context(prefix, @context) do
61
+ output = self._passthrough_object(prefix).__send__(meth, input)
55
62
  end
56
63
 
57
- ret || p.call
64
+ output
58
65
  end
59
66
 
60
67
  end
@@ -2,17 +2,25 @@
2
2
  module Locomotive
3
3
  module Plugin
4
4
  module Liquid
5
- # @private
5
+ # @api internal
6
+ #
7
+ # The methods shared by all tag subclasses.
6
8
  module TagSubclassMethods
7
9
 
8
10
  # Check to see if this tag is enabled in the liquid context and render
9
- # accordingly
11
+ # accordingly.
12
+ #
13
+ # @param context [Liquid::Context] the liquid context object
14
+ # @return the rendered content of the superclass using +render+ or
15
+ # +render_disabled+ as appropriate
10
16
  def render(context)
11
17
  enabled_tags = context.registers[:enabled_plugin_tags]
12
18
  enabled = enabled_tags && enabled_tags.include?(self.class)
13
19
 
14
- p = Proc.new do
15
- if enabled
20
+ output = nil
21
+
22
+ ContextHelpers.add_plugin_object_to_context(self.prefix, context) do
23
+ output = if enabled
16
24
  super
17
25
  elsif self.respond_to?(:render_disabled)
18
26
  self.render_disabled(context)
@@ -21,18 +29,12 @@ module Locomotive
21
29
  end
22
30
  end
23
31
 
24
- ret = nil
25
- rendering_tag(self.class.prefix, enabled, context) do
26
- ret = p.call
27
- end
28
- ret || p.call
32
+ output
29
33
  end
30
34
 
31
- protected
32
-
33
- # This method is overridden by LocomotiveCMS to provide custom
34
- # functionality when the tag is rendering
35
- def rendering_tag(prefix, enabled, context)
35
+ # The prefix for this tag.
36
+ def prefix
37
+ self.class.prefix
36
38
  end
37
39
 
38
40
  end
@@ -6,39 +6,3 @@ require 'haml'
6
6
  require 'mongoid'
7
7
 
8
8
  require 'locomotive/plugin'
9
-
10
- # The overall module for registering plugins
11
- module LocomotivePlugins
12
-
13
- # Get the default ID for the given plugin class
14
- #
15
- # @param plugin_class[Class] the class of the plugin object
16
- def self.default_id(plugin_class)
17
- plugin_class.to_s.split('::').last.underscore
18
- end
19
-
20
- # Register a plugin class with a given ID. If no ID is given, the default ID
21
- # is obtained by calling <tt>default_id(plugin_class)</tt>
22
- #
23
- # @param plugin_class[Class] the class pf the plugin to register
24
- # @param plugin_id[String] the plugin ID to use
25
- def self.register_plugin(plugin_class, plugin_id = nil)
26
- @@registered_plugins ||= {}
27
- plugin_id ||= self.default_id(plugin_class)
28
- @@registered_plugins[plugin_id] = plugin_class
29
- end
30
-
31
- # Get the hash of registered plugin classes, where the keys are the IDs which
32
- # were used to register the plugins
33
- #
34
- # @return [Hash<String, Class>] a hash of plugin IDs to plugin classes
35
- def self.registered_plugins
36
- @@registered_plugins ||= {}
37
- end
38
-
39
- # Remove all plugins from the registered list
40
- def self.clear_registered_plugins
41
- @@registered_plugins = {}
42
- end
43
-
44
- end
data/lib/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module LocomotivePlugins
2
- VERSION = '1.0.0.beta4'
2
+ VERSION = '1.0.0.beta5'
3
3
  end
@@ -0,0 +1,48 @@
1
+
2
+ require 'spec_helper'
3
+
4
+ module Locomotive
5
+ module Plugin
6
+ describe ClassTracker do
7
+
8
+ it 'tracks all the classes which include the module' do
9
+ classes = Locomotive::Plugin.plugin_classes
10
+ classes.should include(MyPlugin)
11
+ classes.should include(UselessPlugin)
12
+ end
13
+
14
+ it 'supports custom trackers' do
15
+ added_classes = []
16
+ num_added_classes = 0
17
+
18
+ Locomotive::Plugin.add_plugin_class_tracker do |plugin_class|
19
+ added_classes << plugin_class
20
+ end
21
+
22
+ Locomotive::Plugin.add_plugin_class_tracker do |plugin_class|
23
+ num_added_classes += 1
24
+ end
25
+
26
+ c = Class.new { include Locomotive::Plugin }
27
+ added_classes.should == [c]
28
+ num_added_classes.should == 1
29
+ end
30
+
31
+ it 'gives custom trackers access to the default ID' do
32
+ added_ids = []
33
+ Locomotive::Plugin.add_plugin_class_tracker do |plugin_class|
34
+ added_ids << plugin_class.default_plugin_id
35
+ end
36
+
37
+ MyNewPlugin = Class.new
38
+ MyNewPlugin.class_eval do
39
+ include Locomotive::Plugin
40
+ end
41
+
42
+ added_ids.count.should == 1
43
+ added_ids.first.should == 'my_new_plugin'
44
+ end
45
+
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,75 @@
1
+
2
+ require 'spec_helper'
3
+
4
+ module Locomotive
5
+ module Plugin
6
+ module Liquid
7
+ describe ContextHelpers do
8
+
9
+ context '#add_plugin_object_to_context' do
10
+
11
+ before(:each) do
12
+ @config = {}
13
+ @plugin = MyPlugin.new(@config)
14
+ @context = ::Liquid::Context.new({}, {}, {site: @site}, true)
15
+
16
+ plugin = @plugin
17
+ @context.registers[:site] = stub do
18
+ stubs(:plugin_object_for_id).with('my_plugin').returns(plugin)
19
+ end
20
+ end
21
+
22
+ it 'should add the object to the context' do
23
+ did_yield = false
24
+ ContextHelpers.add_plugin_object_to_context('my_plugin', @context) do
25
+ did_yield = true
26
+ @context.registers[:plugin_object].should == @plugin
27
+ end
28
+ did_yield.should be_true
29
+ @context.registers[:plugin_object].should be_nil
30
+ end
31
+
32
+ it 'should reset the context object' do
33
+ initial_object = 'initial'
34
+ @context.registers[:plugin_object] = initial_object
35
+
36
+ did_yield = false
37
+ ContextHelpers.add_plugin_object_to_context('my_plugin', @context) do
38
+ did_yield = true
39
+ @context.registers[:plugin_object].should == @plugin
40
+ end
41
+ did_yield.should be_true
42
+ @context.registers[:plugin_object].should == initial_object
43
+ end
44
+
45
+ it 'should do nothing if there is no site object in the context' do
46
+ @context.registers[:site] = nil
47
+
48
+ did_yield = false
49
+ ContextHelpers.add_plugin_object_to_context('my_plugin', @context) do
50
+ did_yield = true
51
+ @context.registers[:plugin_object].should be_nil
52
+ end
53
+ did_yield.should be_true
54
+ @context.registers[:plugin_object].should be_nil
55
+ end
56
+
57
+ it 'should do nothing if the site object has no plugin_object_for method' do
58
+ @context.registers[:site] = Object.new
59
+
60
+ did_yield = false
61
+ ContextHelpers.add_plugin_object_to_context('my_plugin', @context) do
62
+ did_yield = true
63
+ @context.registers[:plugin_object].should be_nil
64
+ end
65
+ did_yield.should be_true
66
+ @context.registers[:plugin_object].should be_nil
67
+ end
68
+
69
+ end
70
+
71
+ end
72
+
73
+ end
74
+ end
75
+ end
@@ -5,73 +5,95 @@ module Locomotive
5
5
  module Plugin
6
6
  describe Liquid do
7
7
 
8
+ context '#setup_liquid_context' do
9
+
10
+ before(:each) do
11
+ @config = {}
12
+ @plugin = MyPlugin.new(@config)
13
+ @context = ::Liquid::Context.new({}, {}, {}, true)
14
+ @plugin.setup_liquid_context('my_plugin', @context)
15
+ end
16
+
17
+ it 'should add a container for the plugin liquid drops' do
18
+ @context['plugins.my_plugin'].class.should == MyPlugin::MyDrop
19
+ end
20
+
21
+ it 'should add a set of enabled liquid tags' do
22
+ @context.registers[:enabled_plugin_tags].class.should == Set
23
+ @context.registers[:enabled_plugin_tags].size.should == 1
24
+ @context.registers[:enabled_plugin_tags].should include(MyPlugin::MyTag::TagSubclass)
25
+ end
26
+
27
+ it 'should add liquid filters' do
28
+ @context.strainer.my_plugin_filter('input').should == 'input'
29
+ expect { @context.strainer.language_plugin_filter('input') }.to raise_error
30
+ end
31
+
32
+ it 'should add the plugin object to the context when invoking drops' do
33
+ ContextHelpers.expects(:add_plugin_object_to_context).with(
34
+ 'my_plugin', @context)
35
+ ::Liquid::Template.parse(
36
+ '{{ plugins.my_plugin.dummy_method }}').render(@context)
37
+ end
38
+
39
+ it 'should add the plugin object to the context when calling filters' do
40
+ ContextHelpers.expects(:add_plugin_object_to_context).with(
41
+ 'my_plugin', @context)
42
+ ::Liquid::Template.parse(
43
+ '{{ "test" | my_plugin_filter }}').render(@context)
44
+ end
45
+
46
+ it 'should add the plugin object to the context when rendering tags' do
47
+ MyPlugin.register_tags('my_plugin')
48
+ ContextHelpers.expects(:add_plugin_object_to_context).with(
49
+ 'my_plugin', @context)
50
+ ::Liquid::Template.parse('{% my_plugin_my_tag %}').render(@context)
51
+ end
52
+
53
+ end
54
+
8
55
  describe '#prefixed_liquid_filter_module' do
9
56
 
10
57
  let(:strainer) { ::Liquid::Strainer.new(::Liquid::Context.new) }
11
58
 
12
59
  before(:each) do
13
- @plugin_with_filter = PluginWithFilter.new({})
60
+ @plugin_with_filter_class = PluginWithFilter
14
61
  end
15
62
 
16
63
  it 'should contain all prefixed methods for provided filter modules' do
17
- mod = @plugin_with_filter.prefixed_liquid_filter_module('prefix')
64
+ mod = @plugin_with_filter_class.prefixed_liquid_filter_module('prefix')
18
65
  mod.public_instance_methods.should include(:prefix_add_http)
19
66
  end
20
67
 
21
68
  it 'should not contain any of the original methods' do
22
- mod = @plugin_with_filter.prefixed_liquid_filter_module('prefix')
69
+ mod = @plugin_with_filter_class.prefixed_liquid_filter_module('prefix')
23
70
  mod.public_instance_methods.should_not include(:add_http)
24
71
  end
25
72
 
26
73
  it 'the prefixed methods should pass through to the original methods' do
27
- strainer.extend(@plugin_with_filter.prefixed_liquid_filter_module('prefix'))
74
+ strainer.extend(@plugin_with_filter_class.prefixed_liquid_filter_module('prefix'))
28
75
  strainer.prefix_add_http('google.com').should == 'http://google.com'
29
76
  strainer.prefix_add_http('http://google.com').should == 'http://google.com'
30
77
  end
31
78
 
32
79
  it 'includes multiple filter modules for one plugin' do
33
- @plugin_with_many_filter_modules = PluginWithManyFilterModules.new({})
34
- mod = @plugin_with_many_filter_modules.prefixed_liquid_filter_module('prefix')
80
+ @plugin_with_many_filter_modules_class = PluginWithManyFilterModules
81
+ mod = @plugin_with_many_filter_modules_class.prefixed_liquid_filter_module('prefix')
35
82
  mod.public_instance_methods.should include(:prefix_add_newline)
36
83
  mod.public_instance_methods.should include(:prefix_remove_http)
37
84
  end
38
85
 
39
86
  it 'works if multiple prefixed modules are mixed into the same object' do
40
- @plugin_with_many_filter_modules = PluginWithManyFilterModules.new({})
87
+ @plugin_with_many_filter_modules_class = PluginWithManyFilterModules
41
88
 
42
- strainer.extend(@plugin_with_filter.prefixed_liquid_filter_module('prefix1'))
43
- strainer.extend(@plugin_with_many_filter_modules.prefixed_liquid_filter_module('prefix2'))
89
+ strainer.extend(@plugin_with_filter_class.prefixed_liquid_filter_module('prefix1'))
90
+ strainer.extend(@plugin_with_many_filter_modules_class.prefixed_liquid_filter_module('prefix2'))
44
91
 
45
92
  strainer.prefix1_add_http('google.com').should == 'http://google.com'
46
93
  strainer.prefix2_add_newline('google.com').should == "google.com\n"
47
94
  strainer.prefix2_remove_http('http://google.com').should == 'google.com'
48
95
  end
49
96
 
50
- it 'should call the filter_method_called hook each time a filter is called' do
51
- # Keep track of how many times filter_method_called is called
52
- Locomotive::Plugin::Liquid::PrefixedFilterModule.module_eval do
53
- attr_reader :count, :prefix, :method
54
-
55
- def filter_method_called(prefix, meth)
56
- @count ||= 0
57
- @count += 1
58
- @prefix = prefix
59
- @method = meth
60
- yield
61
- end
62
- end
63
-
64
- # Call filter methods
65
- strainer.extend(@plugin_with_filter.prefixed_liquid_filter_module('prefix'))
66
- strainer.prefix_add_http('google.com').should == 'http://google.com'
67
- strainer.prefix_add_http('http://google.com').should == 'http://google.com'
68
-
69
- # Make sure filter_method_called was called as expected
70
- strainer.count.should == 2
71
- strainer.prefix.should == 'prefix'
72
- strainer.method.should == :add_http
73
- end
74
-
75
97
  it 'should give the current liquid context object to the passthrough objects' do
76
98
  Locomotive::Plugin::Liquid::PrefixedFilterModule.module_eval do
77
99
  attr_reader :context
@@ -79,7 +101,7 @@ module Locomotive
79
101
  end
80
102
 
81
103
  # Extend the module and create the passthrough object
82
- strainer.extend(@plugin_with_filter.prefixed_liquid_filter_module('prefix'))
104
+ strainer.extend(@plugin_with_filter_class.prefixed_liquid_filter_module('prefix'))
83
105
  strainer.prefix_add_http('google.com').should == 'http://google.com'
84
106
 
85
107
  # Find the context of the passthrough object
@@ -97,6 +119,11 @@ module Locomotive
97
119
  @plugin_class = PluginWithTags
98
120
  @prefixed_tags = @plugin_class.prefixed_liquid_tags('prefix')
99
121
 
122
+ # Clear out existing registered liquid tags and register the ones we
123
+ # want
124
+ ::Liquid::Template.instance_variable_set(:@tags, nil)
125
+ PluginWithTags.register_tags('prefix')
126
+
100
127
  @enabled_tags = []
101
128
  @context = ::Liquid::Context.new
102
129
  @context.registers[:enabled_plugin_tags] = @enabled_tags
@@ -113,13 +140,20 @@ module Locomotive
113
140
  @prefixed_tags['prefix_newline'].should be < PluginWithTags::Newline
114
141
  end
115
142
 
143
+ it 'should register all prefixed tags in liquid' do
144
+ ::Liquid::Template.tags.size.should == 2
145
+ ::Liquid::Template.tags['prefix_paragraph'].should be \
146
+ < PluginWithTags::Paragraph
147
+ ::Liquid::Template.tags['prefix_newline'].should be \
148
+ < PluginWithTags::Newline
149
+ end
150
+
116
151
  it 'only renders a tag if it is enabled in the liquid context' do
117
152
  expected_output = <<-TEMPLATE
118
153
  <p>Some Text</p>
119
154
  Some Text<br />
120
155
  TEMPLATE
121
156
 
122
- register_tags(@prefixed_tags)
123
157
  template = ::Liquid::Template.parse(@raw_template)
124
158
  template.render(@context).should_not == expected_output
125
159
 
@@ -134,7 +168,6 @@ module Locomotive
134
168
  Some Text
135
169
  TEMPLATE
136
170
 
137
- register_tags(@prefixed_tags)
138
171
  template = ::Liquid::Template.parse(@raw_template)
139
172
  template.render(@context).should == expected_output
140
173
  end
@@ -147,48 +180,8 @@ module Locomotive
147
180
  Some Text
148
181
  TEMPLATE
149
182
 
150
- register_tags(@prefixed_tags)
151
- template = ::Liquid::Template.parse(@raw_template)
152
- template.render(@context).should == expected_output
153
- end
154
-
155
- it 'should call the rendering_tag hook each time a tag is rendered' do
156
- TagSubclassMethods.module_eval do
157
- def rendering_tag(prefix, enabled, context)
158
- context.registers[:rendering_tag][self.class] = {
159
- prefix: prefix,
160
- enabled: enabled
161
- }
162
- yield
163
- end
164
- end
165
-
166
- expected_output = <<-TEMPLATE
167
- <p>Some Text</p>
168
- Some Text
169
- TEMPLATE
170
-
171
- @context.registers[:rendering_tag] = {}
172
-
173
- register_tags(@prefixed_tags)
174
- @enabled_tags << @prefixed_tags['prefix_paragraph']
175
183
  template = ::Liquid::Template.parse(@raw_template)
176
184
  template.render(@context).should == expected_output
177
-
178
- paragraph_class = ::Locomotive::PluginWithTags::Paragraph::TagSubclass
179
- newline_class = ::Locomotive::PluginWithTags::Newline::TagSubclass
180
-
181
- hash = @context.registers[:rendering_tag]
182
- hash[paragraph_class].should == { prefix: 'prefix', enabled: true }
183
- hash[newline_class].should == { prefix: 'prefix', enabled: false }
184
- end
185
-
186
- protected
187
-
188
- def register_tags(tags)
189
- tags.each do |name, klass|
190
- ::Liquid::Template.register_tag(name, klass)
191
- end
192
185
  end
193
186
 
194
187
  end