locomotive_plugins 1.0.0.beta2 → 1.0.0.beta3

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -39,6 +39,9 @@ different ID, simply supply the ID in the `register_plugin` call:
39
39
 
40
40
  LocomotivePlugins::register_plugin(BasicAuth, 'auth')
41
41
 
42
+ See the sections below for usage examples. Also, see the
43
+ [documentation](http://rubydoc.info/github/colibri-software/locomotive_plugins/).
44
+
42
45
  ### Initialization
43
46
 
44
47
  To initialize a plugin object, do not override the `initialize` method because
@@ -76,6 +79,12 @@ the Locomotive UI.
76
79
 
77
80
  ### Liquid
78
81
 
82
+ Plugins have the ability to add liquid drops, tags, and filters to
83
+ LocomotiveCMS. These liquid objects will only be accessible to sites which have
84
+ enabled the plugin. All liquid objects have access to
85
+ `@context.registers[:plugin_object]` which supplies the plugin object. This
86
+ gives access to the config hash and other plugin methods.
87
+
79
88
  #### Drops
80
89
 
81
90
  A plugin can add a liquid drop which can be accessed from page templates in
@@ -199,13 +208,31 @@ Here's an example of an HTML config file:
199
208
  <p class="inline-hints">My Hint</p>
200
209
  </li>
201
210
  <li>
202
- <label name="content_type_slugs">Content Types</label>
203
- <select name="content_type_slugs" multiple="multiple">
211
+ <label name="content_type_slug">Content Types</label>
212
+ <select name="content_type_slug" multiple="multiple">
204
213
  {{#each content_types}}
205
214
  <option value="{{ this.slug }}"> {{ this.name }}</option>
206
215
  {{/each}}
207
216
  </select>
208
217
  </li>
218
+ <li>
219
+ <label name="do_awesome_thing">Do the awesome thing?</label>
220
+ <input type="checkbox" name="do_awesome_thing">
221
+ </li>
222
+
223
+ The values of the input fields in this form will be put into the plugin
224
+ object's config hash. Any input coming from a checkbox field will be saved as a
225
+ boolean value, and other input fields will be saved as strings. The keys for
226
+ the hash are taken from the `name` attribute of each input field. So, if in the
227
+ previous example, the "My Plugin Config" field is filled with "Config Value", a
228
+ content type with slug "my\_content\_type" is selected, and the checkbox is
229
+ checked, the config hash will be as follows:
230
+
231
+ {
232
+ "my_plugin_config" => "Config Value",
233
+ "content_type_slug" => "my_content_type",
234
+ "do_awesome_thing" => true
235
+ }
209
236
 
210
237
  ### Database Models
211
238
 
@@ -24,7 +24,7 @@ module Locomotive
24
24
  # normally
25
25
  def prefixed_liquid_tags(prefix)
26
26
  self.liquid_tags.inject({}) do |hash, (tag_name, tag_class)|
27
- hash["#{prefix}_#{tag_name}"] = tag_subclass(tag_class)
27
+ hash["#{prefix}_#{tag_name}"] = tag_subclass(prefix, tag_class)
28
28
  hash
29
29
  end
30
30
  end
@@ -32,10 +32,14 @@ module Locomotive
32
32
  protected
33
33
 
34
34
  # Creates a nested subclass to handle rendering this tag
35
- def tag_subclass(tag_class)
35
+ def tag_subclass(prefix, tag_class)
36
36
  tag_class.class_eval <<-CODE
37
37
  class TagSubclass < #{tag_class.to_s}
38
38
  include ::Locomotive::Plugin::TagSubclassMethods
39
+
40
+ def self.prefix
41
+ '#{prefix}'
42
+ end
39
43
  end
40
44
  CODE
41
45
  tag_class::TagSubclass
@@ -46,39 +50,32 @@ module Locomotive
46
50
  # Gets the module to include as a filter in liquid. It prefixes the
47
51
  # filter methods with the given string
48
52
  def prefixed_liquid_filter_module(prefix)
49
- # Build up a string to eval into the module so we only need to reopen
50
- # it once
51
- strings_to_eval = []
53
+ # Create the module to be returned
54
+ @prefixed_liquid_filter_module = Module.new do
55
+ include ::Locomotive::Plugin::Liquid::PrefixedFilterModule
56
+ end
52
57
 
58
+ # Add the prefixed methods to the module
53
59
  raw_filter_modules = [self.class.liquid_filters].flatten.compact
54
60
  raw_filter_modules.each do |mod|
55
61
  mod.public_instance_methods.each do |meth|
56
- strings_to_eval << <<-CODE
57
- def #{prefix}_#{meth}(input)
58
- self._passthrough_filter_call_for_#{prefix}('#{meth}', input)
62
+ @prefixed_liquid_filter_module.module_eval do
63
+ define_method(:"#{prefix}_#{meth}") do |input|
64
+ self._passthrough_filter_call(prefix, meth, input)
59
65
  end
60
- CODE
66
+ end
61
67
  end
62
68
  end
63
69
 
64
- strings_to_eval << <<-CODE
70
+ # Add a method which returns the modules to include for this prefix
71
+ @prefixed_liquid_filter_module.module_eval do
65
72
  protected
66
73
 
67
- def _passthrough_object_for_#{prefix}
68
- @_passthrough_object_for_#{prefix} ||= \
69
- self._build_passthrough_object([#{raw_filter_modules.join(',')}])
74
+ define_method(:"_modules_for_#{prefix}") do
75
+ raw_filter_modules
70
76
  end
71
-
72
- def _passthrough_filter_call_for_#{prefix}(meth, input)
73
- self._passthrough_object_for_#{prefix}.public_send(meth, input)
74
- end
75
- CODE
76
-
77
- # Eval the dynamic methods in
78
- @prefixed_liquid_filter_module = Module.new do
79
- include ::Locomotive::Plugin::Liquid::PrefixedFilterModule
80
77
  end
81
- @prefixed_liquid_filter_module.class_eval strings_to_eval.join("\n")
78
+
82
79
  @prefixed_liquid_filter_module
83
80
  end
84
81
 
@@ -10,12 +10,51 @@ module Locomotive
10
10
 
11
11
  protected
12
12
 
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
+
13
18
  def _build_passthrough_object(modules_to_extend)
14
- Object.new.tap do |obj|
15
- modules_to_extend.each do |mod|
16
- obj.extend(mod)
17
- end
19
+ obj = ::Liquid::Strainer.new(@context)
20
+
21
+ modules_to_extend.each do |mod|
22
+ obj.extend(mod)
23
+ end
24
+
25
+ obj
26
+ end
27
+
28
+ def _passthrough_object(prefix)
29
+ @_passthrough_objects ||= {}
30
+ obj = @_passthrough_objects[prefix]
31
+
32
+ # Return it if we have it
33
+ return obj if obj
34
+
35
+ # Otherwise, build it
36
+ modules_for_prefix_meth = :"_modules_for_#{prefix}"
37
+ if self.respond_to?(modules_for_prefix_meth)
38
+ modules = self.__send__(modules_for_prefix_meth)
39
+ else
40
+ modules = []
41
+ end
42
+
43
+ @_passthrough_objects[prefix] = self._build_passthrough_object(modules)
44
+ end
45
+
46
+ def _passthrough_filter_call(prefix, meth, input)
47
+ p = Proc.new do
48
+ self._passthrough_object(prefix).__send__(meth, input)
49
+ end
50
+
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
18
55
  end
56
+
57
+ ret || p.call
19
58
  end
20
59
 
21
60
  end
@@ -4,18 +4,37 @@ module Locomotive
4
4
  module Liquid
5
5
  # @private
6
6
  module TagSubclassMethods
7
+
7
8
  # Check to see if this tag is enabled in the liquid context and render
8
9
  # accordingly
9
10
  def render(context)
10
- enabled = context.registers[:enabled_plugin_tags]
11
- if enabled && enabled.include?(self.class)
12
- super
13
- elsif self.respond_to?(:render_disabled)
14
- self.render_disabled(context)
15
- else
16
- ''
11
+ enabled_tags = context.registers[:enabled_plugin_tags]
12
+ enabled = enabled_tags && enabled_tags.include?(self.class)
13
+
14
+ p = Proc.new do
15
+ if enabled
16
+ super
17
+ elsif self.respond_to?(:render_disabled)
18
+ self.render_disabled(context)
19
+ else
20
+ ''
21
+ end
22
+ end
23
+
24
+ ret = nil
25
+ rendering_tag(self.class.prefix, enabled, context) do
26
+ ret = p.call
17
27
  end
28
+ ret || p.call
18
29
  end
30
+
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)
36
+ end
37
+
19
38
  end
20
39
  end
21
40
  end
data/lib/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module LocomotivePlugins
2
- VERSION = '1.0.0.beta2'
2
+ VERSION = '1.0.0.beta3'
3
3
  end
@@ -7,6 +7,8 @@ module Locomotive
7
7
 
8
8
  describe '#prefixed_liquid_filter_module' do
9
9
 
10
+ let(:strainer) { ::Liquid::Strainer.new(::Liquid::Context.new) }
11
+
10
12
  before(:each) do
11
13
  @plugin_with_filter = PluginWithFilter.new({})
12
14
  end
@@ -22,10 +24,9 @@ module Locomotive
22
24
  end
23
25
 
24
26
  it 'the prefixed methods should pass through to the original methods' do
25
- obj = Object.new
26
- obj.extend(@plugin_with_filter.prefixed_liquid_filter_module('prefix'))
27
- obj.prefix_add_http('google.com').should == 'http://google.com'
28
- obj.prefix_add_http('http://google.com').should == 'http://google.com'
27
+ strainer.extend(@plugin_with_filter.prefixed_liquid_filter_module('prefix'))
28
+ strainer.prefix_add_http('google.com').should == 'http://google.com'
29
+ strainer.prefix_add_http('http://google.com').should == 'http://google.com'
29
30
  end
30
31
 
31
32
  it 'includes multiple filter modules for one plugin' do
@@ -38,13 +39,54 @@ module Locomotive
38
39
  it 'works if multiple prefixed modules are mixed into the same object' do
39
40
  @plugin_with_many_filter_modules = PluginWithManyFilterModules.new({})
40
41
 
41
- obj = Object.new
42
- obj.extend(@plugin_with_filter.prefixed_liquid_filter_module('prefix1'))
43
- obj.extend(@plugin_with_many_filter_modules.prefixed_liquid_filter_module('prefix2'))
42
+ strainer.extend(@plugin_with_filter.prefixed_liquid_filter_module('prefix1'))
43
+ strainer.extend(@plugin_with_many_filter_modules.prefixed_liquid_filter_module('prefix2'))
44
+
45
+ strainer.prefix1_add_http('google.com').should == 'http://google.com'
46
+ strainer.prefix2_add_newline('google.com').should == "google.com\n"
47
+ strainer.prefix2_remove_http('http://google.com').should == 'google.com'
48
+ end
49
+
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
+ it 'should give the current liquid context object to the passthrough objects' do
76
+ Locomotive::Plugin::Liquid::PrefixedFilterModule.module_eval do
77
+ attr_reader :context
78
+ def passthrough_objects ; @_passthrough_objects ; end
79
+ end
80
+
81
+ # Extend the module and create the passthrough object
82
+ strainer.extend(@plugin_with_filter.prefixed_liquid_filter_module('prefix'))
83
+ strainer.prefix_add_http('google.com').should == 'http://google.com'
44
84
 
45
- obj.prefix1_add_http('google.com').should == 'http://google.com'
46
- obj.prefix2_add_newline('google.com').should == "google.com\n"
47
- obj.prefix2_remove_http('http://google.com').should == 'google.com'
85
+ # Find the context of the passthrough object
86
+ obj = strainer.passthrough_objects['prefix']
87
+ def obj.context ; @context ; end
88
+
89
+ obj.context.should == strainer.context
48
90
  end
49
91
 
50
92
  end
@@ -110,6 +152,37 @@ module Locomotive
110
152
  template.render(@context).should == expected_output
111
153
  end
112
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
+ template = ::Liquid::Template.parse(@raw_template)
176
+ 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
+
113
186
  protected
114
187
 
115
188
  def register_tags(tags)
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.beta2
4
+ version: 1.0.0.beta3
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: 2012-11-23 00:00:00.000000000 Z
12
+ date: 2012-12-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: locomotive_liquid