ruby-handlebars 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4850c228d3a84c6701b524aecbb493f801bc4927
4
+ data.tar.gz: d3d9abdc1cae0ab1a3625f500ec6f39a30c8cc75
5
+ SHA512:
6
+ metadata.gz: e9e72431e3c5687b375b8064dbdb99ce089d395aca63d7d0ae09f65d75742f67f9479c91a7f5ebfa0d204f957aaca7d4b468dab2325ec1238dc42ac9f624dff4
7
+ data.tar.gz: c24ae4750d88e834db222b5830b242ae0a8571295aca85e3c38bc6acc895895c51f7d846608336b95573cc2304d6f784fbd3dcfe6336317d66f22cd49db2361d
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Vincent
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/README.md ADDED
@@ -0,0 +1,8 @@
1
+ # ruby-handlebars
2
+
3
+ [![Build Status](https://travis-ci.org/vincent-psarga/ruby-handlebars.svg?branch=master)](https://travis-ci.org/vincent-psarga/ruby-handlebars)
4
+ [![Code Climate](https://codeclimate.com/github/vincent-psarga/ruby-handlebars/badges/gpa.svg)](https://codeclimate.com/github/vincent-psarga/ruby-handlebars)
5
+ [![Test Coverage](https://codeclimate.com/github/vincent-psarga/ruby-handlebars/badges/coverage.svg)](https://codeclimate.com/github/vincent-psarga/ruby-handlebars)
6
+
7
+ Pure Ruby library for Handlebars templates.
8
+ The main goal of this library is to simplify the use of Ruby and Handlebars on Windows machine. If you do not have any need of working on Windows, take a look at [handlebars.rb](https://github.com/cowboyd/handlebars.rb) that uses the real Handlebars library.
@@ -0,0 +1,82 @@
1
+ require_relative 'ruby-handlebars/parser'
2
+ require_relative 'ruby-handlebars/tree'
3
+ require_relative 'ruby-handlebars/template'
4
+ require_relative 'ruby-handlebars/helper'
5
+
6
+ module Handlebars
7
+ class Handlebars
8
+ include Context
9
+
10
+ def initialize
11
+ @helpers = {}
12
+ @partials = {}
13
+ register_default_helpers
14
+ end
15
+
16
+ def compile(template)
17
+ Template.new(self, template_to_ast(template))
18
+ end
19
+
20
+ def register_helper(name, &fn)
21
+ @helpers[name.to_s] = Helper.new(self, fn)
22
+ end
23
+
24
+ def get_helper(name)
25
+ @helpers[name.to_s]
26
+ end
27
+
28
+ def register_partial(name, content)
29
+ @partials[name.to_s] = Template.new(self, template_to_ast(content))
30
+ end
31
+
32
+ def get_partial(name)
33
+ @partials[name.to_s]
34
+ end
35
+
36
+ def set_context(ctx)
37
+ @data = ctx
38
+ end
39
+
40
+ private
41
+ def template_to_ast(content)
42
+ Transform.new.apply(Parser.new.parse(content))
43
+ end
44
+
45
+ def register_default_helpers
46
+ register_if_helper
47
+ register_each_helper
48
+ end
49
+
50
+ def register_if_helper
51
+ register_helper('if') do |context, condition, block, else_block|
52
+ condition = !condition.empty? if condition.respond_to?(:empty?)
53
+
54
+ if condition
55
+ block.fn(context)
56
+ elsif else_block
57
+ else_block.fn(context)
58
+ else
59
+ ""
60
+ end
61
+ end
62
+ end
63
+
64
+ def register_each_helper
65
+ register_helper('each') do |context, items, block, else_block|
66
+ current_this = context.get('this')
67
+
68
+ if items.empty? && else_block
69
+ result = else_block.fn(context)
70
+ else
71
+ result = items.map do |item|
72
+ context.add_item(:this, item)
73
+ block.fn(context)
74
+ end.join('')
75
+ end
76
+
77
+ context.add_item(:this, current_this)
78
+ result
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,41 @@
1
+ module Handlebars
2
+ module Context
3
+ def get(path)
4
+ items = path.split('.')
5
+
6
+ current = @data
7
+ until items.empty?
8
+ current = get_attribute(current, items.shift)
9
+ end
10
+
11
+ current
12
+ end
13
+
14
+ def add_item(key, value)
15
+ @data[key] = value
16
+ end
17
+
18
+ private
19
+
20
+ def get_attribute(item, attribute)
21
+ sym_attr = attribute.to_sym
22
+ str_attr = attribute.to_s
23
+
24
+ if item.respond_to?('[]')
25
+ if item.has_key?(sym_attr)
26
+ return item[sym_attr]
27
+ elsif item.has_key?(str_attr)
28
+ return item[str_attr]
29
+ end
30
+ end
31
+
32
+ if item.instance_variables.include?("@#{attribute}")
33
+ return item.instance_variable_get("@#{attribute}")
34
+ end
35
+
36
+ if item.respond_to?(sym_attr)
37
+ return item.send(sym_attr)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,41 @@
1
+ require_relative 'tree'
2
+
3
+ module Handlebars
4
+ class Helper
5
+ def initialize(hbs, fn)
6
+ @hbs = hbs
7
+ @fn = fn
8
+ end
9
+
10
+ def apply(context, arguments = [], block = [])
11
+ arguments = [arguments] unless arguments.is_a? Array
12
+ args = [context] + arguments.map {|arg| arg.eval(context)} + split_block(block || [])
13
+
14
+ @fn.call(*args)
15
+ end
16
+
17
+ def split_block(block)
18
+ helper_block = Tree::Block.new([])
19
+ inverse_block = Tree::Block.new([])
20
+
21
+ receiver = helper_block
22
+ else_found = false
23
+
24
+ block.each do |item|
25
+ if item.is_a?(Tree::Replacement) && item.is_else?
26
+ receiver = inverse_block
27
+ else_found = true
28
+ next
29
+ end
30
+
31
+ receiver.add_item(item)
32
+ end
33
+
34
+ if else_found
35
+ return [helper_block, inverse_block]
36
+ else
37
+ return [helper_block]
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,66 @@
1
+ require 'pry'
2
+ require 'parslet'
3
+
4
+ module Handlebars
5
+ class Parser < Parslet::Parser
6
+ rule(:space) { match('\s').repeat(1) }
7
+ rule(:space?) { space.maybe }
8
+ rule(:dot) { str('.') }
9
+ rule(:gt) { str('>')}
10
+ rule(:hash) { str('#')}
11
+ rule(:slash) { str('/')}
12
+ rule(:ocurly) { str('{')}
13
+ rule(:ccurly) { str('}')}
14
+
15
+ rule(:docurly) { ocurly >> ocurly }
16
+ rule(:dccurly) { ccurly >> ccurly }
17
+
18
+ rule(:identifier) { match['a-zA-Z0-9_\?'].repeat(1) }
19
+ rule(:path) { identifier >> (dot >> identifier).repeat }
20
+
21
+ rule(:template_content) { match('[^{}]').repeat(1).as(:template_content) }
22
+
23
+ rule(:replacement) { docurly >> space? >> path.as(:replaced_item) >> space? >> dccurly}
24
+ rule(:safe_replacement) { ocurly >> replacement >> ccurly }
25
+
26
+ rule(:sq_string) { match("'") >> match("[^']").repeat(1).as(:str_content) >> match("'") }
27
+ rule(:dq_string) { match('"') >> match('[^"]').repeat(1).as(:str_content) >> match('"') }
28
+ rule(:string) { sq_string | dq_string }
29
+
30
+ rule(:parameter) { (path | string).as(:parameter_name) }
31
+ rule(:parameters) { parameter >> (space >> parameter).repeat }
32
+
33
+ rule(:unsafe_helper) { docurly >> space? >> identifier.as(:helper_name) >> (space? >> parameters.as(:parameters)).maybe >> space? >> dccurly}
34
+ rule(:safe_helper) { ocurly >> helper >> ccurly }
35
+
36
+ rule(:helper) { unsafe_helper | safe_helper }
37
+
38
+ rule(:block_helper) {
39
+ docurly >>
40
+ hash >>
41
+ identifier.capture(:helper_name).as(:helper_name) >>
42
+ (space >> parameters.as(:parameters)).maybe >>
43
+ space? >>
44
+ dccurly >>
45
+ scope {
46
+ block
47
+ } >>
48
+ dynamic { |src, scope|
49
+ docurly >> slash >> str(scope.captures[:helper_name]) >> dccurly
50
+ }
51
+ }
52
+
53
+ rule(:partial) {
54
+ docurly >>
55
+ gt >>
56
+ space? >>
57
+ identifier.as(:partial_name) >>
58
+ space? >>
59
+ dccurly
60
+ }
61
+
62
+ rule(:block) { (template_content | replacement | safe_replacement | helper | partial | block_helper ).repeat.as(:block_items) }
63
+
64
+ root :block
65
+ end
66
+ end
@@ -0,0 +1,18 @@
1
+ require_relative 'context'
2
+
3
+ module Handlebars
4
+ class Template
5
+ def initialize(hbs, ast)
6
+ @hbs = hbs
7
+ @ast = ast
8
+ end
9
+
10
+ def call(args)
11
+ if args.is_a? Hash
12
+ @hbs.set_context(args)
13
+ end
14
+
15
+ @ast.eval(@hbs)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,102 @@
1
+ require 'colorize'
2
+
3
+ module Handlebars
4
+ module Tree
5
+ class TreeItem < Struct
6
+ def eval(context)
7
+ _eval(context)
8
+ end
9
+ end
10
+
11
+ class TemplateContent < TreeItem.new(:content)
12
+ def _eval(context)
13
+ return content
14
+ end
15
+ end
16
+
17
+ class Replacement < TreeItem.new(:item)
18
+ def _eval(context)
19
+ if context.get_helper(item.to_s).nil?
20
+ context.get(item.to_s)
21
+ else
22
+ context.get_helper(item.to_s).apply(context)
23
+ end
24
+ end
25
+
26
+ def is_else?
27
+ item.to_s == 'else'
28
+ end
29
+ end
30
+
31
+ class String < TreeItem.new(:content)
32
+ def _eval(context)
33
+ return content
34
+ end
35
+ end
36
+
37
+ class Parameter < TreeItem.new(:name)
38
+ def _eval(context)
39
+ if name.is_a?(Parslet::Slice)
40
+ context.get(name.to_s)
41
+ else
42
+ name._eval(context)
43
+ end
44
+ end
45
+ end
46
+
47
+ class Helper < TreeItem.new(:name, :parameters, :block)
48
+ def _eval(context)
49
+ context.get_helper(name.to_s).apply(context, parameters, block)
50
+ end
51
+ end
52
+
53
+ class Partial < TreeItem.new(:partial_name)
54
+ def _eval(context)
55
+ context.get_partial(partial_name.to_s).call(context)
56
+ end
57
+ end
58
+
59
+ class Block < TreeItem.new(:items)
60
+ def _eval(context)
61
+ items.map {|item| item._eval(context)}.join()
62
+ end
63
+ alias :fn :_eval
64
+
65
+ def add_item(i)
66
+ items << i
67
+ end
68
+ end
69
+ end
70
+
71
+ class Transform < Parslet::Transform
72
+ rule(template_content: simple(:content)) {Tree::TemplateContent.new(content)}
73
+ rule(replaced_item: simple(:item)) {Tree::Replacement.new(item)}
74
+ rule(str_content: simple(:content)) {Tree::String.new(content)}
75
+ rule(parameter_name: simple(:name)) {Tree::Parameter.new(name)}
76
+
77
+ rule(
78
+ helper_name: simple(:name),
79
+ parameters: subtree(:parameters)
80
+ ) {
81
+ Tree::Helper.new(name, parameters)
82
+ }
83
+
84
+ rule(
85
+ helper_name: simple(:name),
86
+ block_items: subtree(:block_items)
87
+ ) {
88
+ Tree::Helper.new(name, [], block_items)
89
+ }
90
+
91
+ rule(
92
+ helper_name: simple(:name),
93
+ parameters: subtree(:parameters),
94
+ block_items: subtree(:block_items)
95
+ ) {
96
+ Tree::Helper.new(name, parameters, block_items)
97
+ }
98
+
99
+ rule(partial_name: simple(:partial_name)) {Tree::Partial.new(partial_name)}
100
+ rule(block_items: subtree(:block_items)) {Tree::Block.new(block_items)}
101
+ end
102
+ end
metadata ADDED
@@ -0,0 +1,195 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-handlebars
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Vincent Pretre
8
+ - Hiptest R&D
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2015-03-06 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: parslet
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: colorize
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: 0.7.5
35
+ - - "~>"
36
+ - !ruby/object:Gem::Version
37
+ version: '0.7'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: 0.7.5
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.7'
48
+ - !ruby/object:Gem::Dependency
49
+ name: pry
50
+ requirement: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: pry-stack_explorer
64
+ requirement: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ type: :development
70
+ prerelease: false
71
+ version_requirements: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ - !ruby/object:Gem::Dependency
77
+ name: rspec
78
+ requirement: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 3.1.0
83
+ - - "~>"
84
+ - !ruby/object:Gem::Version
85
+ version: '3.1'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: 3.1.0
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '3.1'
96
+ - !ruby/object:Gem::Dependency
97
+ name: rspec-mocks
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: 3.1.3
103
+ - - "~>"
104
+ - !ruby/object:Gem::Version
105
+ version: '3.1'
106
+ type: :development
107
+ prerelease: false
108
+ version_requirements: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: 3.1.3
113
+ - - "~>"
114
+ - !ruby/object:Gem::Version
115
+ version: '3.1'
116
+ - !ruby/object:Gem::Dependency
117
+ name: codeclimate-test-reporter
118
+ requirement: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: 0.4.6
123
+ - - "~>"
124
+ - !ruby/object:Gem::Version
125
+ version: '0.4'
126
+ type: :development
127
+ prerelease: false
128
+ version_requirements: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: 0.4.6
133
+ - - "~>"
134
+ - !ruby/object:Gem::Version
135
+ version: '0.4'
136
+ - !ruby/object:Gem::Dependency
137
+ name: jeweler
138
+ requirement: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - ">="
141
+ - !ruby/object:Gem::Version
142
+ version: 2.0.1
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '2.0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: 2.0.1
153
+ - - "~>"
154
+ - !ruby/object:Gem::Version
155
+ version: '2.0'
156
+ description:
157
+ email: v.pretre@hiptest.net
158
+ executables: []
159
+ extensions: []
160
+ extra_rdoc_files:
161
+ - LICENSE
162
+ - README.md
163
+ files:
164
+ - LICENSE
165
+ - README.md
166
+ - lib/ruby-handlebars.rb
167
+ - lib/ruby-handlebars/context.rb
168
+ - lib/ruby-handlebars/helper.rb
169
+ - lib/ruby-handlebars/parser.rb
170
+ - lib/ruby-handlebars/template.rb
171
+ - lib/ruby-handlebars/tree.rb
172
+ homepage: https://github.com/vincent-psarga/ruby-handlebars
173
+ licenses: []
174
+ metadata: {}
175
+ post_install_message:
176
+ rdoc_options: []
177
+ require_paths:
178
+ - lib
179
+ required_ruby_version: !ruby/object:Gem::Requirement
180
+ requirements:
181
+ - - ">="
182
+ - !ruby/object:Gem::Version
183
+ version: '0'
184
+ required_rubygems_version: !ruby/object:Gem::Requirement
185
+ requirements:
186
+ - - ">="
187
+ - !ruby/object:Gem::Version
188
+ version: '0'
189
+ requirements: []
190
+ rubyforge_project:
191
+ rubygems_version: 2.4.3
192
+ signing_key:
193
+ specification_version: 4
194
+ summary: Pure Ruby library for Handlebars templates
195
+ test_files: []