cerubis 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.
Files changed (75) hide show
  1. data/.gitignore +10 -0
  2. data/.travis.yml +14 -0
  3. data/Gemfile +15 -0
  4. data/README.md +111 -0
  5. data/Rakefile +15 -0
  6. data/TODO.md +31 -0
  7. data/cerubis.gemspec +22 -0
  8. data/examples/blocks.rb +20 -0
  9. data/examples/full/blocks/script_block.rb +8 -0
  10. data/examples/full/config.rb +14 -0
  11. data/examples/full/example.rb +25 -0
  12. data/examples/full/helpers/html_helpers.rb +13 -0
  13. data/examples/full/helpers/include_helper.rb +15 -0
  14. data/examples/full/models/page.rb +17 -0
  15. data/examples/full/models/site.rb +13 -0
  16. data/examples/full/templates/_footer.cerubis +1 -0
  17. data/examples/full/templates/_header.cerubis +1 -0
  18. data/examples/full/templates/main.cerubis +31 -0
  19. data/examples/helpers.rb +22 -0
  20. data/examples/html.rb +18 -0
  21. data/examples/variables.rb +10 -0
  22. data/lib/cerubis.rb +55 -0
  23. data/lib/cerubis/block.rb +27 -0
  24. data/lib/cerubis/block_node.rb +37 -0
  25. data/lib/cerubis/blocks/if.rb +8 -0
  26. data/lib/cerubis/blocks/loop.rb +20 -0
  27. data/lib/cerubis/blocks/unless.rb +9 -0
  28. data/lib/cerubis/condition.rb +59 -0
  29. data/lib/cerubis/context.rb +30 -0
  30. data/lib/cerubis/helper.rb +12 -0
  31. data/lib/cerubis/matcher.rb +19 -0
  32. data/lib/cerubis/method.rb +19 -0
  33. data/lib/cerubis/node.rb +27 -0
  34. data/lib/cerubis/objects/array.rb +4 -0
  35. data/lib/cerubis/objects/fixnum.rb +4 -0
  36. data/lib/cerubis/objects/float.rb +4 -0
  37. data/lib/cerubis/objects/hash.rb +4 -0
  38. data/lib/cerubis/objects/string.rb +4 -0
  39. data/lib/cerubis/parser.rb +125 -0
  40. data/lib/cerubis/syntax_error.rb +4 -0
  41. data/lib/cerubis/template.rb +21 -0
  42. data/lib/cerubis/text_node.rb +10 -0
  43. data/lib/cerubis/variable_replacement.rb +34 -0
  44. data/lib/cerubis/version.rb +3 -0
  45. data/test/all.rb +3 -0
  46. data/test/cerubis/block_node_test.rb +36 -0
  47. data/test/cerubis/blocks/if_test.rb +24 -0
  48. data/test/cerubis/blocks/loop_test.rb +25 -0
  49. data/test/cerubis/blocks/unless_test.rb +25 -0
  50. data/test/cerubis/condition_test.rb +142 -0
  51. data/test/cerubis/context_test.rb +33 -0
  52. data/test/cerubis/helper_test.rb +17 -0
  53. data/test/cerubis/matcher_test.rb +20 -0
  54. data/test/cerubis/method_test.rb +60 -0
  55. data/test/cerubis/parser_test.rb +48 -0
  56. data/test/cerubis/template_test.rb +38 -0
  57. data/test/cerubis/text_node_test.rb +16 -0
  58. data/test/cerubis_test.rb +31 -0
  59. data/test/matchers/test_block_name.rb +25 -0
  60. data/test/matchers/test_close_block.rb +25 -0
  61. data/test/matchers/test_conditions.rb +21 -0
  62. data/test/matchers/test_helpers.rb +21 -0
  63. data/test/matchers/test_object_method.rb +37 -0
  64. data/test/matchers/test_open_block.rb +57 -0
  65. data/test/matchers/test_operators.rb +29 -0
  66. data/test/matchers/test_variable.rb +37 -0
  67. data/test/methods/test_array_methods.rb +21 -0
  68. data/test/methods/test_fixnum_methods.rb +6 -0
  69. data/test/methods/test_float_methods.rb +6 -0
  70. data/test/methods/test_hash_methods.rb +11 -0
  71. data/test/methods/test_string_methods.rb +11 -0
  72. data/test/nodes/test_node_defaults.rb +30 -0
  73. data/test/rendered_test.rb +159 -0
  74. data/test/test_helper.rb +34 -0
  75. metadata +149 -0
@@ -0,0 +1,4 @@
1
+ class Cerubis
2
+ class SyntaxError < Exception
3
+ end
4
+ end
@@ -0,0 +1,21 @@
1
+ class Cerubis
2
+ class Template
3
+ attr :content
4
+ attr :context
5
+ attr :nodes
6
+
7
+ def initialize(content, context={})
8
+ @content = content
9
+ @context = Context.new(context)
10
+ @nodes = Parser.new(@content, :parent => self).nodes
11
+ end
12
+
13
+ def compile
14
+ @template ||= nodes.map(&:render).join
15
+ end
16
+
17
+ alias :to_html :compile
18
+ alias :to_text :compile
19
+ alias :to_s :compile
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ class Cerubis
2
+ class TextNode
3
+ include Node
4
+ include VariableReplacement
5
+
6
+ def render
7
+ replace_variables(pre_render)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,34 @@
1
+ class Cerubis
2
+ module VariableReplacement
3
+ def replace_variables(str, ctx=context)
4
+ str.gsub(Matcher::Variable) do |variable|
5
+ match_var = variable.match(Matcher::Variable)[1]
6
+ if match = match_var.match(Matcher::Helpers)
7
+ helper_method = match[1]
8
+ helper_args = match[2].to_s.split(Matcher::CommaOutsideQuote).map do |arg|
9
+ ctx.get(arg.strip)
10
+ end
11
+
12
+ begin
13
+ if helper_mod = Cerubis.helpers[helper_method.to_sym] || Cerubis.helpers[helper_method]
14
+ helper = Helper.new(ctx)
15
+ helper.extend helper_mod
16
+
17
+ if has_public_method?(helper, helper_method)
18
+ helper.send(helper_method, *helper_args)
19
+ end
20
+ end
21
+ rescue ArgumentError
22
+ raise SyntaxError, "A wrong number of arguments were passed to '#{helper_method}'"
23
+ end
24
+ else
25
+ ctx.get(match_var)
26
+ end
27
+ end
28
+ end
29
+
30
+ def has_public_method?(obj, meth)
31
+ obj.public_methods.include?(meth) || obj.public_methods.include?(meth.to_sym)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,3 @@
1
+ class Cerubis
2
+ VERSION = "0.0.1"
3
+ end
data/test/all.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'test_helper'
2
+
3
+ Dir["**/*_test.rb"].each { |path| require File.expand_path(path) }
@@ -0,0 +1,36 @@
1
+ require 'test_helper'
2
+ require 'nodes/test_node_defaults'
3
+
4
+ class Cerubis::BlockNodeTest < MiniTest::Unit::TestCase
5
+ include TestNodeDefaults
6
+
7
+ def test_open_and_close_block_text_removed_on_render
8
+ content = <<-STR
9
+ {{#if true}}
10
+ Foo Content
11
+ {{/if}}
12
+ STR
13
+
14
+ node = Cerubis::BlockNode.new(content, :parent => StubObject.new)
15
+ refute_match /\{\{/, node.render
16
+ end
17
+
18
+ def test_variable_replacement
19
+ content = <<-STR
20
+ {{#if true}}
21
+ <h1>{{title}}</h1>
22
+ {{/if}}
23
+ STR
24
+
25
+ node = Cerubis::BlockNode.new(content, options)
26
+ html = Capybara::Node::Simple.new(node.render)
27
+
28
+ assert html.has_selector?('h1', :text => 'Foo Title')
29
+ refute_match /\{\{/, node.render
30
+ end
31
+
32
+ private
33
+ def class_name
34
+ Cerubis::BlockNode
35
+ end
36
+ end
@@ -0,0 +1,24 @@
1
+ require 'test_helper'
2
+
3
+ class Cerubis::Blocks::IfTest < MiniTest::Unit::TestCase
4
+ def setup
5
+ parent = StubObject.new
6
+ content = <<-STR
7
+ {{#if true}}
8
+ Foo Content
9
+ {{/if}}
10
+ STR
11
+
12
+ node = Cerubis::BlockNode.new(content, :parent => parent)
13
+ @output = node.render
14
+ @block = node.block
15
+ end
16
+
17
+ def test_block_is_instance_of_if_block_class
18
+ assert_instance_of Cerubis::Blocks::If, @block
19
+ end
20
+
21
+ def test_block_condition_is_true
22
+ assert @block.true?
23
+ end
24
+ end
@@ -0,0 +1,25 @@
1
+ require 'test_helper'
2
+
3
+ class Cerubis::Blocks::LoopTest < MiniTest::Unit::TestCase
4
+ def setup
5
+ context = Cerubis::Context.new(:items => [1,2,3])
6
+ parent = StubObject.new(:context => context)
7
+ content = <<-STR
8
+ {{#loop item in items}}
9
+ <p>{{ item }}</p>
10
+ {{/loop}}
11
+ STR
12
+
13
+ node = Cerubis::BlockNode.new(content, :parent => parent)
14
+ @output = node.render
15
+ @block = node.block
16
+ end
17
+
18
+ def test_block_is_instance_of_loop_block_class
19
+ assert_instance_of Cerubis::Blocks::Loop, @block
20
+ end
21
+
22
+ def test_block_condition_is_true
23
+ assert @block.true?
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ require 'test_helper'
2
+
3
+ class Cerubis::Blocks::UnlessTest < MiniTest::Unit::TestCase
4
+ def setup
5
+ context = Cerubis::Context.new
6
+ parent = StubObject.new(:context => context)
7
+ content = <<-STR
8
+ {{#unless false}}
9
+ Foo Content
10
+ {{/unless}}
11
+ STR
12
+
13
+ node = Cerubis::BlockNode.new(content, :parent => parent)
14
+ @output = node.render
15
+ @block = node.block
16
+ end
17
+
18
+ def test_block_is_instance_of_unless_block_class
19
+ assert_instance_of Cerubis::Blocks::Unless, @block
20
+ end
21
+
22
+ def test_block_condition_is_true
23
+ assert @block.true?
24
+ end
25
+ end
@@ -0,0 +1,142 @@
1
+ require 'test_helper'
2
+
3
+ class Cerubis::ConditionTest < MiniTest::Unit::TestCase
4
+ def test_context_objects
5
+ condition_str = '2 > 1'
6
+ context = Cerubis::Context.new
7
+ condition = Cerubis::Condition.new(condition_str, :type => :if, :context => context)
8
+
9
+ assert condition.true?
10
+ assert_equal ['2', '>', '1'], condition.parsed_content
11
+ end
12
+
13
+ def test_parsed_content
14
+ condition_str = 'item > item2'
15
+ context = Cerubis::Context.new(:item => 2, :item2 => 1)
16
+ condition = Cerubis::Condition.new(condition_str, :type => :if, :context => context)
17
+
18
+ assert condition.true?
19
+ assert_equal 2, condition.context_objects.first
20
+ assert_equal 1, condition.context_objects.last
21
+ end
22
+
23
+ def test_if_true_condition
24
+ condition_str = 'true'
25
+ context = Cerubis::Context.new
26
+ condition = Cerubis::Condition.new(condition_str, :type => :if, :context => context)
27
+
28
+ assert condition.true?
29
+ end
30
+
31
+ def test_if_2_greater_than_1
32
+ condition_str = '2 > 1'
33
+ context = Cerubis::Context.new
34
+ condition = Cerubis::Condition.new(condition_str, :type => :if, :context => context)
35
+
36
+ assert condition.true?
37
+ end
38
+
39
+ def test_if_object_method
40
+ condition_str = 'item.empty?'
41
+ item = StubObject.new(:empty? => true)
42
+ context = Cerubis::Context.new(:item => item)
43
+ condition = Cerubis::Condition.new(condition_str, :type => :if, :context => context)
44
+
45
+ assert condition.true?
46
+ end
47
+
48
+ def test_if_1_greater_than_2_fails
49
+ condition_str = '1 > 2'
50
+ context = Cerubis::Context.new
51
+ condition = Cerubis::Condition.new(condition_str, :type => :if, :context => context)
52
+
53
+ refute condition.true?
54
+ end
55
+
56
+ def test_in_operator_used_in_if_block
57
+ assert_raises Cerubis::SyntaxError do
58
+ condition_str = 'item in items'
59
+ context = Cerubis::Context.new
60
+ condition = Cerubis::Condition.new(condition_str, :type => :if, :context => context)
61
+ condition.true?
62
+ end
63
+ end
64
+
65
+ def test_loop_in_block_true
66
+ condition_str = 'item in items'
67
+ context = Cerubis::Context.new(:items => [1,2,3,4])
68
+ condition = Cerubis::Condition.new(condition_str, :type => :loop, :context => context)
69
+ assert condition.true?
70
+ end
71
+
72
+ def test_loop_in_block_false
73
+ condition_str = 'item in items'
74
+ context = Cerubis::Context.new(:items => [])
75
+ condition = Cerubis::Condition.new(condition_str, :type => :loop, :context => context)
76
+ refute condition.true?
77
+ end
78
+
79
+ def test_double_equals_operator
80
+ condition_str = '1 == 1'
81
+ context = Cerubis::Context.new
82
+ condition = Cerubis::Condition.new(condition_str, :type => :if, :context => context)
83
+
84
+ assert condition.true?
85
+ end
86
+
87
+ def test_triple_equals_operator
88
+ condition_str = 'foo === foo'
89
+ context = Cerubis::Context.new(:foo => 'foo str')
90
+ condition = Cerubis::Condition.new(condition_str, :type => :if, :context => context)
91
+
92
+ assert condition.true?
93
+ end
94
+
95
+ def test_not_equals_operator
96
+ condition_str = 'foo != bar'
97
+ context = Cerubis::Context.new(:foo => 'foo str', :bar => 'bar str')
98
+ condition = Cerubis::Condition.new(condition_str, :type => :if, :context => context)
99
+
100
+ assert condition.true?
101
+ end
102
+
103
+ def test_less_than_operator
104
+ condition_str = '1 < 2'
105
+ context = Cerubis::Context.new
106
+ condition = Cerubis::Condition.new(condition_str, :type => :if, :context => context)
107
+
108
+ assert condition.true?
109
+ end
110
+
111
+ def test_greater_than_operator
112
+ condition_str = '2 > 1'
113
+ context = Cerubis::Context.new
114
+ condition = Cerubis::Condition.new(condition_str, :type => :if, :context => context)
115
+
116
+ assert condition.true?
117
+ end
118
+
119
+ def test_less_than_or_equals_operator
120
+ context = Cerubis::Context.new
121
+
122
+ condition_str = '1 <= 2'
123
+ condition = Cerubis::Condition.new(condition_str, :type => :if, :context => context)
124
+ assert condition.true?
125
+
126
+ condition_str = '2 <= 2'
127
+ condition = Cerubis::Condition.new(condition_str, :type => :if, :context => context)
128
+ assert condition.true?
129
+ end
130
+
131
+ def test_greater_than_or_equals_operator
132
+ context = Cerubis::Context.new
133
+
134
+ condition_str = '2 >= 1'
135
+ condition = Cerubis::Condition.new(condition_str, :type => :if, :context => context)
136
+ assert condition.true?
137
+
138
+ condition_str = '2 >= 2'
139
+ condition = Cerubis::Condition.new(condition_str, :type => :if, :context => context)
140
+ assert condition.true?
141
+ end
142
+ end
@@ -0,0 +1,33 @@
1
+ require 'test_helper'
2
+
3
+ class Cerubis::ContextTest < MiniTest::Unit::TestCase
4
+ def test_context_returns_true
5
+ context = Cerubis::Context.new
6
+ assert_equal true, context.get('true')
7
+ end
8
+
9
+ def test_context_returns_false
10
+ context = Cerubis::Context.new
11
+ assert_equal false, context.get('false')
12
+ end
13
+
14
+ def test_context_returns_integer
15
+ context = Cerubis::Context.new
16
+ assert_equal 1, context.get('1')
17
+ end
18
+
19
+ def test_context_returns_float
20
+ context = Cerubis::Context.new
21
+ assert_equal 1.5, context.get('1.5')
22
+ end
23
+
24
+ def test_context_returns_item_from_context
25
+ context = Cerubis::Context.new(:item => :foo)
26
+ assert_equal :foo, context.get('item')
27
+ end
28
+
29
+ def test_context_returns_string_without_single_quotes
30
+ context = Cerubis::Context.new
31
+ assert_equal 'foo', context.get("'foo'")
32
+ end
33
+ end
@@ -0,0 +1,17 @@
1
+ require 'test_helper'
2
+
3
+ class Cerubis::HelperTest < MiniTest::Unit::TestCase
4
+ def test_helper_can_access_context
5
+ context = Cerubis::Context.new(:bar => 'bar str')
6
+ helper = Cerubis::Helper.new(context)
7
+ helper.extend FooHelper
8
+
9
+ assert_equal 'bar str', helper.foo_helper('bar')
10
+ end
11
+
12
+ module FooHelper
13
+ def foo_helper(obj)
14
+ "#{context[obj.to_sym]}"
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,20 @@
1
+ require 'test_helper'
2
+ require 'matchers/test_operators'
3
+ require 'matchers/test_block_name'
4
+ require 'matchers/test_object_method'
5
+ require 'matchers/test_open_block'
6
+ require 'matchers/test_close_block'
7
+ require 'matchers/test_conditions'
8
+ require 'matchers/test_variable'
9
+ require 'matchers/test_helpers'
10
+
11
+ class Cerubis::MatcherTest < MiniTest::Unit::TestCase
12
+ include TestOperators
13
+ include TestBlockName
14
+ include TestObjectMethod
15
+ include TestOpenBlock
16
+ include TestCloseBlock
17
+ include TestConditions
18
+ include TestVariable
19
+ include TestHelpers
20
+ end
@@ -0,0 +1,60 @@
1
+ require 'test_helper'
2
+ require 'methods/test_array_methods'
3
+ require 'methods/test_string_methods'
4
+ require 'methods/test_float_methods'
5
+ require 'methods/test_fixnum_methods'
6
+ require 'methods/test_hash_methods'
7
+
8
+ class Cerubis::MethodTest < MiniTest::Unit::TestCase
9
+ include TestArrayMethods
10
+ include TestStringMethods
11
+ include TestFloatMethods
12
+ include TestFixnumMethods
13
+ include TestHashMethods
14
+
15
+ def setup
16
+ @obj = FooObj.new
17
+ end
18
+
19
+ def test_method_is_allowed
20
+ assert @obj.cerubis_respond_to?(:foo)
21
+ end
22
+
23
+ def test_nested_method_is_allowed
24
+ assert @obj.foo.cerubis_respond_to?(:baz)
25
+ end
26
+
27
+ def test_method_is_not_allowed
28
+ refute @obj.cerubis_respond_to?(:bar)
29
+ end
30
+
31
+ def test_nested_method_is_not_allowed
32
+ refute @obj.foo.cerubis_respond_to?(:cux)
33
+ end
34
+ end
35
+
36
+ class FooObj
37
+ include Cerubis::Method
38
+ cerubis_method :foo
39
+
40
+ def foo
41
+ BazObj.new
42
+ end
43
+
44
+ def bar
45
+ "Not Allowed"
46
+ end
47
+ end
48
+
49
+ class BazObj
50
+ include Cerubis::Method
51
+ cerubis_method :baz
52
+
53
+ def baz
54
+ "Allowed"
55
+ end
56
+
57
+ def cux
58
+ "Not Allowed"
59
+ end
60
+ end