locomotivecms-solid 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +10 -0
  5. data/Gemfile +6 -0
  6. data/LICENSE +20 -0
  7. data/README.md +152 -0
  8. data/Rakefile +7 -0
  9. data/lib/locomotivecms-solid.rb +2 -0
  10. data/lib/solid.rb +48 -0
  11. data/lib/solid/arguments.rb +26 -0
  12. data/lib/solid/block.rb +13 -0
  13. data/lib/solid/conditional_block.rb +35 -0
  14. data/lib/solid/context_error.rb +2 -0
  15. data/lib/solid/default_security_rules.rb +24 -0
  16. data/lib/solid/element.rb +51 -0
  17. data/lib/solid/engine.rb +4 -0
  18. data/lib/solid/extensions.rb +17 -0
  19. data/lib/solid/iterable.rb +18 -0
  20. data/lib/solid/liquid_extensions.rb +87 -0
  21. data/lib/solid/liquid_extensions/assign_tag.rb +21 -0
  22. data/lib/solid/liquid_extensions/for_tag.rb +102 -0
  23. data/lib/solid/liquid_extensions/if_tag.rb +44 -0
  24. data/lib/solid/liquid_extensions/unless_tag.rb +13 -0
  25. data/lib/solid/liquid_extensions/variable.rb +34 -0
  26. data/lib/solid/method_whitelist.rb +56 -0
  27. data/lib/solid/model_drop.rb +119 -0
  28. data/lib/solid/parser.rb +108 -0
  29. data/lib/solid/parser/ripper.rb +220 -0
  30. data/lib/solid/parser/ruby_parser.rb +88 -0
  31. data/lib/solid/tag.rb +11 -0
  32. data/lib/solid/template.rb +24 -0
  33. data/lib/solid/version.rb +3 -0
  34. data/locomotivecms-solid.gemspec +26 -0
  35. data/spec/solid/arguments_spec.rb +314 -0
  36. data/spec/solid/block_spec.rb +39 -0
  37. data/spec/solid/conditional_block_spec.rb +39 -0
  38. data/spec/solid/default_security_rules_spec.rb +180 -0
  39. data/spec/solid/element_examples.rb +67 -0
  40. data/spec/solid/liquid_extensions/assign_tag_spec.rb +27 -0
  41. data/spec/solid/liquid_extensions/for_tag_spec.rb +48 -0
  42. data/spec/solid/liquid_extensions/if_tag_spec.rb +64 -0
  43. data/spec/solid/liquid_extensions/unless_tag_spec.rb +54 -0
  44. data/spec/solid/liquid_extensions/variable_spec.rb +25 -0
  45. data/spec/solid/model_drop_spec.rb +26 -0
  46. data/spec/solid/parser/ripper_spec.rb +14 -0
  47. data/spec/solid/parser/ruby_parser_spec.rb +7 -0
  48. data/spec/solid/tag_spec.rb +26 -0
  49. data/spec/solid/template_spec.rb +37 -0
  50. data/spec/spec_helper.rb +8 -0
  51. data/spec/support/class_highjacker_examples.rb +33 -0
  52. data/spec/support/method_whitelist_matchers.rb +17 -0
  53. data/spec/support/parser_examples.rb +261 -0
  54. data/spec/support/tag_highjacker_examples.rb +33 -0
  55. metadata +204 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3c7a10871a1bd686fd52392900ae05429a57efa5
4
+ data.tar.gz: 18d617cded1dc8a1abd28548be9c40aee0343e86
5
+ SHA512:
6
+ metadata.gz: fb7ffdbd7aeb5a8755ce513be15d39f02a3f0196eb70ed69c853098845feac19b82409656fd7c354210ce26a234015d4f06c13c9ac8feaad7f17f806e35279ec
7
+ data.tar.gz: a9cb451974d001e7ebe5a34872dab917090481f1f8b79011a263e24883987d0ec9142278f8375f45bcf578ec60851999076fdee66ceb0987b9b1814fe97c2b6c
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,10 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+ - jruby-19mode
6
+ - rbx-19mode
7
+ matrix:
8
+ allow_failures:
9
+ - rvm: jruby-19mode
10
+ - rvm: rbx-19mode
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in solid.gemspec
4
+ gemspec
5
+
6
+ # gem 'locomotivecms-liquid', path: '/Users/didier/Documents/LocomotiveCMS/gems/liquid'
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Tigerlily, http://tigerlilyapps.com/
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,152 @@
1
+ # Solid
2
+
3
+ Solid aim to provide a easier and nicer API to create custom Liquid tags and blocks
4
+
5
+ ## Installation
6
+
7
+ Due to a name conflict the gem is called tigerlily-solid. So to use it:
8
+
9
+ ```
10
+ gem 'tigerlily-solid', :require => 'solid'
11
+ ```
12
+
13
+ ## Build Status [![Build Status](https://secure.travis-ci.org/tigerlily/solid.png)](http://travis-ci.org/tigerlily/solid)
14
+
15
+ ## Tags
16
+
17
+ To create a new tag, you just have to:
18
+
19
+ - Extend `Solid::Tag`
20
+ - Define a `display` method
21
+ - Give a `tag_name`
22
+
23
+ ```ruby
24
+ class DummyTag < Solid::Tag
25
+
26
+ tag_name :dummy # register in Liquid under the name of `dummy`
27
+
28
+ def display
29
+ 'dummy !!!'
30
+ end
31
+
32
+ end
33
+ ```
34
+
35
+ ```html
36
+ <p>{% dummy %}<p>
37
+ ```
38
+
39
+ ## Arguments
40
+
41
+ This is the simpliest tag ever but, Solid tags can receive rich arguments:
42
+
43
+ ```ruby
44
+ class TypeOfTag < Solid::Tag
45
+
46
+ tag_name :typeof
47
+
48
+ def display(*values)
49
+ ''.tap do |output|
50
+ values.each do |value|
51
+ output << "<p>Type of #{value} is #{value.class.name}</p>"
52
+ end
53
+ end
54
+ end
55
+
56
+ end
57
+ ```
58
+
59
+ ```html
60
+ {% capture myvar %}eggspam{% endcapture %}
61
+ {% typeof "foo", 42, 4.2, myvar, myoption:"bar", otheroption:myvar %}
62
+ <!-- produce -->
63
+ <p>Type of "foo" is String</p>
64
+ <p>Type of 42 is Integer</p>
65
+ <p>Type of 4.2 is Float</p>
66
+ <p>Type of "eggspam" is String</p>
67
+ <p>Type of {:myoption=>"bar", :otheroption=>"eggspam"} is Hash</p>
68
+ ```
69
+
70
+ ## Context attributes
71
+
72
+ If there is some "global variables" in your liquid context you can declare that
73
+ your tag need to access it:
74
+
75
+ ```ruby
76
+ class HelloTag < Solid::Tag
77
+
78
+ tag_name :hello
79
+
80
+ context_attribute :current_user
81
+
82
+ def display
83
+ "Hello #{current_user.name} !"
84
+ end
85
+
86
+ end
87
+ ```
88
+
89
+ ```html
90
+ <p>{% hello %}</p>
91
+ <!-- produce -->
92
+ <p>Hello Homer</p>
93
+ ```
94
+ ## Blocks
95
+
96
+ Block are just tags with a body. They perform the same argument parsing.
97
+ To render the block body from it's `display` method you just have to `yield`:
98
+
99
+ ```ruby
100
+ class PBlock < Solid::Block
101
+
102
+ tag_name :p
103
+
104
+ def display(options)
105
+ "<p class='#{options[:class]}'>#{yield}</p>"
106
+ end
107
+
108
+ end
109
+ ```
110
+
111
+ ```html
112
+ {% p class:"content" %}
113
+ It works !
114
+ {% endp %}
115
+ <!-- produce -->
116
+ <p class="content">It works !</p>
117
+ ```
118
+
119
+ Of course you are free to yield once, multiple times or even never.
120
+
121
+ ## Conditional Blocks
122
+
123
+ Conditional blocks are blocks with two bodies. If you yield `true` you will receive the main block
124
+ and if you yield `false` you will receive the else block:
125
+
126
+ ```ruby
127
+ class IfAuthorizedToTag < Solid::ConditionalBlock
128
+
129
+ tag_name :if_authorized_to
130
+
131
+ context_attribute :current_user
132
+
133
+ def display(permission)
134
+ yield(current_user.authorized_to?(permission))
135
+ end
136
+
137
+ end
138
+ ```
139
+
140
+ ```html
141
+ {% if_authorized_to "publish" %}
142
+ You are authorized !
143
+ {% else %}
144
+ Get out !
145
+ {% endif_authorized_to %}
146
+ ```
147
+
148
+ ## License
149
+
150
+ Solid is released under the MIT license:
151
+
152
+ http://www.opensource.org/licenses/MIT
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ Bundler::GemHelper.install_tasks
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task default: :spec
@@ -0,0 +1,2 @@
1
+ # Thanks to this file, the gem will be automatically loaded at startup.
2
+ require 'solid'
data/lib/solid.rb ADDED
@@ -0,0 +1,48 @@
1
+ require 'liquid'
2
+
3
+ module Solid
4
+ BASE_PATH = File.join(File.expand_path(File.dirname(__FILE__)), 'solid')
5
+
6
+ require File.join(BASE_PATH, 'extensions')
7
+
8
+ autoload :Argument, File.join(BASE_PATH, 'argument')
9
+ autoload :Arguments, File.join(BASE_PATH, 'arguments')
10
+ autoload :Block, File.join(BASE_PATH, 'block')
11
+ autoload :ConditionalBlock, File.join(BASE_PATH, 'conditional_block')
12
+ autoload :ContextError, File.join(BASE_PATH, 'context_error')
13
+ autoload :Element, File.join(BASE_PATH, 'element')
14
+ autoload :Iterable, File.join(BASE_PATH, 'iterable')
15
+ autoload :MethodWhitelist, File.join(BASE_PATH, 'method_whitelist')
16
+ autoload :Parser, File.join(BASE_PATH, 'parser')
17
+ autoload :Tag, File.join(BASE_PATH, 'tag')
18
+ autoload :Template, File.join(BASE_PATH, 'template')
19
+ autoload :VERSION, File.join(BASE_PATH, 'version')
20
+
21
+ if defined?(Rails) # Rails only features
22
+ autoload :ModelDrop, File.join(BASE_PATH, 'model_drop')
23
+ require File.join(BASE_PATH, 'engine')
24
+ end
25
+
26
+ require File.join(BASE_PATH, 'liquid_extensions')
27
+
28
+ class << self
29
+
30
+ def unproxify(object)
31
+ class_name = object.class.name
32
+ if class_name && class_name.end_with?('::LiquidDropClass')
33
+ return object.instance_variable_get('@object')
34
+ end
35
+ object
36
+ end
37
+
38
+ def to_liquid(object, context)
39
+ object = object.to_liquid
40
+ object.context = context if object.respond_to?(:context=)
41
+ object
42
+ end
43
+
44
+ end
45
+
46
+ SyntaxError = Class.new(Liquid::SyntaxError)
47
+
48
+ end
@@ -0,0 +1,26 @@
1
+ class Solid::Arguments
2
+ include Enumerable
3
+
4
+ def self.parse(string)
5
+ new("[#{string}]").parse!
6
+ end
7
+
8
+ attr_accessor :values
9
+
10
+ def initialize(string)
11
+ @string = string
12
+ end
13
+
14
+ def parse!
15
+ self.values = Solid::Parser.parse(@string)
16
+ self
17
+ end
18
+
19
+ def each(*args, &block)
20
+ values.each(*args, &block)
21
+ end
22
+
23
+ def interpolate(context)
24
+ values.evaluate(context)
25
+ end
26
+ end
@@ -0,0 +1,13 @@
1
+ class Solid::Block < Liquid::Block
2
+
3
+ include Solid::Element
4
+
5
+ def render(context)
6
+ with_context(context) do
7
+ display(*arguments.interpolate(context)) do
8
+ super
9
+ end
10
+ end
11
+ end
12
+
13
+ end
@@ -0,0 +1,35 @@
1
+ class Solid::ConditionalBlock < Liquid::Block
2
+ include Solid::Element
3
+
4
+ def initialize(tag_name, variable, tokens, context = {})
5
+ @blocks = []
6
+ push_block!
7
+ super
8
+ end
9
+
10
+ def render(context)
11
+ with_context(context) do
12
+ display(*arguments.interpolate(context)) do |condition_satisfied|
13
+ block = condition_satisfied ? @blocks.first : @blocks[1]
14
+ render_all(block, context) if block
15
+ end
16
+ end
17
+ end
18
+
19
+ def unknown_tag(tag, markup, tokens, context = {})
20
+ if tag == 'else'
21
+ push_block!
22
+ else
23
+ super
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def push_block!
30
+ block = []
31
+ @blocks.push(block)
32
+ @nodelist = block
33
+ end
34
+
35
+ end
@@ -0,0 +1,2 @@
1
+ class Solid::ContextError < Exception
2
+ end
@@ -0,0 +1,24 @@
1
+ Solid::MethodWhitelist
2
+ .allow(
3
+ BasicObject => [:!, :!=, :==],
4
+ Object => [:present?, :blank?, :in?, :to_json],
5
+ Kernel => [:nil?, :!~],
6
+ Module => [:==],
7
+ Enumerable => [:sort],
8
+ Comparable => [:<, :<=, :==, :>, :>=, :between?],
9
+ Numeric => [:blank?, :+@,
10
+ :second, :seconds, :minute, :minutes, :hour, :hours, :day, :days, :week, :weeks,
11
+ :bytes, :kilobytes, :megabytes, :gigabytes, :terabytes, :petabytes, :exabytes],
12
+ Integer => [:multiple_of?, :month, :months, :year, :years, :to_json],
13
+ ).deny(
14
+ Module => [:const_get, :const_set, :const_defined?, :freeze, :ancestors],
15
+ Class => [:new, :allocate, :superclass],
16
+ )
17
+
18
+ if defined?(JSON::Ext::Generator::GeneratorMethods::Fixnum) &&
19
+ defined?(JSON::Ext::Generator::GeneratorMethods::Bignum)
20
+ Solid::MethodWhitelist.allow(
21
+ JSON::Ext::Generator::GeneratorMethods::Fixnum => [:to_json],
22
+ JSON::Ext::Generator::GeneratorMethods::Bignum => [:to_json],
23
+ )
24
+ end
@@ -0,0 +1,51 @@
1
+ module Solid::Element
2
+
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ base.send(:include, Solid::Iterable)
6
+ end
7
+
8
+ def initialize(tag_name, arguments_string, tokens, context = {})
9
+ super
10
+ @arguments = Solid::Arguments.parse(arguments_string)
11
+ end
12
+
13
+ def arguments
14
+ @arguments
15
+ end
16
+
17
+ def with_context(context)
18
+ previous_context = @current_context
19
+ @current_context = context
20
+ yield
21
+ ensure
22
+ @current_context = previous_context
23
+ end
24
+
25
+ def current_context
26
+ @current_context or raise Solid::ContextError.new("There is currently no context, do you forget to call render ?")
27
+ end
28
+
29
+ def display(*args)
30
+ raise NotImplementedError.new("Solid::Element implementations SHOULD define a #display method")
31
+ end
32
+
33
+ module ClassMethods
34
+
35
+ def tag_name(value=nil)
36
+ if value
37
+ @tag_name = value
38
+ Liquid::Template.register_tag(value.to_s, self)
39
+ end
40
+ @tag_name
41
+ end
42
+
43
+ def context_attribute(name)
44
+ define_method(name) do
45
+ Solid.unproxify(current_context[name.to_s])
46
+ end
47
+ end
48
+
49
+ end
50
+
51
+ end
@@ -0,0 +1,4 @@
1
+ module Solid
2
+ class Engine < Rails::Engine
3
+ end
4
+ end
@@ -0,0 +1,17 @@
1
+ module LiquidSafe
2
+ def to_liquid
3
+ self
4
+ end
5
+ end
6
+
7
+ class Symbol
8
+ include LiquidSafe
9
+ end
10
+
11
+ class Regexp
12
+ include LiquidSafe
13
+ end
14
+
15
+ class Time
16
+ extend LiquidSafe
17
+ end