handlebars 0.0.2 → 0.2.0

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 (47) hide show
  1. data/.gitignore +1 -1
  2. data/.gitmodules +3 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +1 -1
  5. data/README.mdown +44 -0
  6. data/Rakefile +3 -0
  7. data/handlebars.gemspec +19 -13
  8. data/lib/handlebars.rb +4 -3
  9. data/lib/handlebars/context.rb +37 -0
  10. data/lib/handlebars/version.rb +1 -1
  11. data/spec/handlebars_spec.rb +40 -0
  12. data/spike.rb +17 -0
  13. data/vendor/handlebars/.gitignore +6 -0
  14. data/vendor/handlebars/.jshintrc +50 -0
  15. data/vendor/handlebars/.npmignore +11 -0
  16. data/vendor/handlebars/Gemfile +5 -0
  17. data/vendor/handlebars/LICENSE +20 -0
  18. data/vendor/handlebars/README.markdown +315 -0
  19. data/vendor/handlebars/Rakefile +116 -0
  20. data/vendor/handlebars/bench/benchwarmer.js +149 -0
  21. data/vendor/handlebars/bench/handlebars.js +163 -0
  22. data/vendor/handlebars/bin/handlebars +139 -0
  23. data/vendor/handlebars/lib/handlebars.js +14 -0
  24. data/vendor/handlebars/lib/handlebars/base.js +101 -0
  25. data/vendor/handlebars/lib/handlebars/compiler/ast.js +103 -0
  26. data/vendor/handlebars/lib/handlebars/compiler/base.js +27 -0
  27. data/vendor/handlebars/lib/handlebars/compiler/compiler.js +808 -0
  28. data/vendor/handlebars/lib/handlebars/compiler/index.js +7 -0
  29. data/vendor/handlebars/lib/handlebars/compiler/printer.js +137 -0
  30. data/vendor/handlebars/lib/handlebars/compiler/visitor.js +13 -0
  31. data/vendor/handlebars/lib/handlebars/runtime.js +68 -0
  32. data/vendor/handlebars/lib/handlebars/utils.js +68 -0
  33. data/vendor/handlebars/package.json +25 -0
  34. data/vendor/handlebars/spec/acceptance_spec.rb +101 -0
  35. data/vendor/handlebars/spec/parser_spec.rb +264 -0
  36. data/vendor/handlebars/spec/qunit_spec.js +1067 -0
  37. data/vendor/handlebars/spec/spec_helper.rb +157 -0
  38. data/vendor/handlebars/spec/tokenizer_spec.rb +254 -0
  39. data/vendor/handlebars/src/handlebars.l +42 -0
  40. data/vendor/handlebars/src/handlebars.yy +99 -0
  41. metadata +93 -77
  42. data/README.md +0 -39
  43. data/lib/handlebars/generator.rb +0 -4
  44. data/lib/handlebars/parser.rb +0 -240
  45. data/spec/generator_spec.rb +0 -5
  46. data/spec/parser_spec.rb +0 -163
  47. data/spec/spec_helper.rb +0 -17
@@ -0,0 +1,99 @@
1
+ %start root
2
+
3
+ %%
4
+
5
+ root
6
+ : program EOF { return $1; }
7
+ ;
8
+
9
+ program
10
+ : statements simpleInverse statements { $$ = new yy.ProgramNode($1, $3); }
11
+ | statements { $$ = new yy.ProgramNode($1); }
12
+ | "" { $$ = new yy.ProgramNode([]); }
13
+ ;
14
+
15
+ statements
16
+ : statement { $$ = [$1]; }
17
+ | statements statement { $1.push($2); $$ = $1; }
18
+ ;
19
+
20
+ statement
21
+ : openInverse program closeBlock { $$ = new yy.InverseNode($1, $2, $3); }
22
+ | openBlock program closeBlock { $$ = new yy.BlockNode($1, $2, $3); }
23
+ | mustache { $$ = $1; }
24
+ | partial { $$ = $1; }
25
+ | CONTENT { $$ = new yy.ContentNode($1); }
26
+ | COMMENT { $$ = new yy.CommentNode($1); }
27
+ ;
28
+
29
+ openBlock
30
+ : OPEN_BLOCK inMustache CLOSE { $$ = new yy.MustacheNode($2[0], $2[1]); }
31
+ ;
32
+
33
+ openInverse
34
+ : OPEN_INVERSE inMustache CLOSE { $$ = new yy.MustacheNode($2[0], $2[1]); }
35
+ ;
36
+
37
+ closeBlock
38
+ : OPEN_ENDBLOCK path CLOSE { $$ = $2; }
39
+ ;
40
+
41
+ mustache
42
+ : OPEN inMustache CLOSE { $$ = new yy.MustacheNode($2[0], $2[1]); }
43
+ | OPEN_UNESCAPED inMustache CLOSE { $$ = new yy.MustacheNode($2[0], $2[1], true); }
44
+ ;
45
+
46
+
47
+ partial
48
+ : OPEN_PARTIAL path CLOSE { $$ = new yy.PartialNode($2); }
49
+ | OPEN_PARTIAL path path CLOSE { $$ = new yy.PartialNode($2, $3); }
50
+ ;
51
+
52
+ simpleInverse
53
+ : OPEN_INVERSE CLOSE { }
54
+ ;
55
+
56
+ inMustache
57
+ : path params hash { $$ = [[$1].concat($2), $3]; }
58
+ | path params { $$ = [[$1].concat($2), null]; }
59
+ | path hash { $$ = [[$1], $2]; }
60
+ | path { $$ = [[$1], null]; }
61
+ ;
62
+
63
+ params
64
+ : params param { $1.push($2); $$ = $1; }
65
+ | param { $$ = [$1]; }
66
+ ;
67
+
68
+ param
69
+ : path { $$ = $1; }
70
+ | STRING { $$ = new yy.StringNode($1); }
71
+ | INTEGER { $$ = new yy.IntegerNode($1); }
72
+ | BOOLEAN { $$ = new yy.BooleanNode($1); }
73
+ ;
74
+
75
+ hash
76
+ : hashSegments { $$ = new yy.HashNode($1); }
77
+ ;
78
+
79
+ hashSegments
80
+ : hashSegments hashSegment { $1.push($2); $$ = $1; }
81
+ | hashSegment { $$ = [$1]; }
82
+ ;
83
+
84
+ hashSegment
85
+ : ID EQUALS path { $$ = [$1, $3]; }
86
+ | ID EQUALS STRING { $$ = [$1, new yy.StringNode($3)]; }
87
+ | ID EQUALS INTEGER { $$ = [$1, new yy.IntegerNode($3)]; }
88
+ | ID EQUALS BOOLEAN { $$ = [$1, new yy.BooleanNode($3)]; }
89
+ ;
90
+
91
+ path
92
+ : pathSegments { $$ = new yy.IdNode($1); }
93
+ ;
94
+
95
+ pathSegments
96
+ : pathSegments SEP ID { $1.push($3); $$ = $1; }
97
+ | ID { $$ = [$1]; }
98
+ ;
99
+
metadata CHANGED
@@ -1,107 +1,123 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: handlebars
3
- version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 0
8
- - 2
9
- version: 0.0.2
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ prerelease:
10
6
  platform: ruby
11
- authors:
12
- - Martin Schuerrer
7
+ authors:
8
+ - Charles Lowell
13
9
  autorequire:
14
10
  bindir: bin
15
11
  cert_chain: []
16
-
17
- date: 2010-09-10 00:00:00 +02:00
18
- default_executable:
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
21
- name: bundler
12
+ date: 2012-03-16 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: therubyracer
16
+ requirement: &2156214780 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.10.0beta1
22
+ type: :runtime
22
23
  prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
24
+ version_requirements: *2156214780
25
+ - !ruby/object:Gem::Dependency
26
+ name: commonjs
27
+ requirement: &2156214000 !ruby/object:Gem::Requirement
24
28
  none: false
25
- requirements:
26
- - - ">="
27
- - !ruby/object:Gem::Version
28
- segments:
29
- - 1
30
- - 0
31
- - 0
32
- version: 1.0.0
33
- type: :development
34
- version_requirements: *id001
35
- - !ruby/object:Gem::Dependency
36
- name: rspec
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 0.2.3
33
+ type: :runtime
37
34
  prerelease: false
38
- requirement: &id002 !ruby/object:Gem::Requirement
35
+ version_requirements: *2156214000
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ requirement: &2156213220 !ruby/object:Gem::Requirement
39
39
  none: false
40
- requirements:
40
+ requirements:
41
41
  - - ~>
42
- - !ruby/object:Gem::Version
43
- segments:
44
- - 2
45
- - 0
46
- - 0
47
- version: 2.0.0
42
+ - !ruby/object:Gem::Version
43
+ version: '2.0'
48
44
  type: :development
49
- version_requirements: *id002
50
- description: A straight port of handlebars.js to ruby. Currently unfinished, if you've got a complete version let me know so I'll release the name to you
51
- email:
52
- - martin@schuerrer.org
45
+ prerelease: false
46
+ version_requirements: *2156213220
47
+ description: Uses the actual JavaScript implementation of Handlebars, but supports
48
+ using Ruby objects as template contexts and Ruby procs as view functions and named
49
+ helpers
50
+ email:
51
+ - cowboyd@thefrontside.net
53
52
  executables: []
54
-
55
53
  extensions: []
56
-
57
54
  extra_rdoc_files: []
58
-
59
- files:
55
+ files:
60
56
  - .gitignore
57
+ - .gitmodules
58
+ - .rspec
61
59
  - Gemfile
62
- - README.md
60
+ - README.mdown
63
61
  - Rakefile
64
62
  - handlebars.gemspec
65
63
  - lib/handlebars.rb
66
- - lib/handlebars/generator.rb
67
- - lib/handlebars/parser.rb
64
+ - lib/handlebars/context.rb
68
65
  - lib/handlebars/version.rb
69
- - spec/generator_spec.rb
70
- - spec/parser_spec.rb
71
- - spec/spec_helper.rb
72
- has_rdoc: true
73
- homepage: http://github.com/MSch/handlebars-ruby
66
+ - spec/handlebars_spec.rb
67
+ - spike.rb
68
+ - vendor/handlebars/.gitignore
69
+ - vendor/handlebars/.jshintrc
70
+ - vendor/handlebars/.npmignore
71
+ - vendor/handlebars/Gemfile
72
+ - vendor/handlebars/Gemfile.lock
73
+ - vendor/handlebars/LICENSE
74
+ - vendor/handlebars/README.markdown
75
+ - vendor/handlebars/Rakefile
76
+ - vendor/handlebars/bench/benchwarmer.js
77
+ - vendor/handlebars/bench/handlebars.js
78
+ - vendor/handlebars/bin/handlebars
79
+ - vendor/handlebars/lib/handlebars.js
80
+ - vendor/handlebars/lib/handlebars/base.js
81
+ - vendor/handlebars/lib/handlebars/compiler/ast.js
82
+ - vendor/handlebars/lib/handlebars/compiler/base.js
83
+ - vendor/handlebars/lib/handlebars/compiler/compiler.js
84
+ - vendor/handlebars/lib/handlebars/compiler/index.js
85
+ - vendor/handlebars/lib/handlebars/compiler/printer.js
86
+ - vendor/handlebars/lib/handlebars/compiler/visitor.js
87
+ - vendor/handlebars/lib/handlebars/runtime.js
88
+ - vendor/handlebars/lib/handlebars/utils.js
89
+ - vendor/handlebars/package.json
90
+ - vendor/handlebars/spec/acceptance_spec.rb
91
+ - vendor/handlebars/spec/parser_spec.rb
92
+ - vendor/handlebars/spec/qunit_spec.js
93
+ - vendor/handlebars/spec/spec_helper.rb
94
+ - vendor/handlebars/spec/tokenizer_spec.rb
95
+ - vendor/handlebars/src/handlebars.l
96
+ - vendor/handlebars/src/handlebars.yy
97
+ - vendor/handlebars/lib/handlebars/compiler/parser.js
98
+ homepage: http://github.com/cowboyd/handlebars.rb
74
99
  licenses: []
75
-
76
100
  post_install_message:
77
101
  rdoc_options: []
78
-
79
- require_paths:
102
+ require_paths:
80
103
  - lib
81
- required_ruby_version: !ruby/object:Gem::Requirement
104
+ required_ruby_version: !ruby/object:Gem::Requirement
82
105
  none: false
83
- requirements:
84
- - - ">="
85
- - !ruby/object:Gem::Version
86
- segments:
87
- - 0
88
- version: "0"
89
- required_rubygems_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
111
  none: false
91
- requirements:
92
- - - ">="
93
- - !ruby/object:Gem::Version
94
- segments:
95
- - 1
96
- - 3
97
- - 6
98
- version: 1.3.6
112
+ requirements:
113
+ - - ! '>='
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
99
116
  requirements: []
100
-
101
117
  rubyforge_project: handlebars
102
- rubygems_version: 1.3.7
118
+ rubygems_version: 1.8.17
103
119
  signing_key:
104
120
  specification_version: 3
105
- summary: handlebars.js port to ruby
106
- test_files: []
107
-
121
+ summary: Ruby bindings for the handlebars.js templating library
122
+ test_files:
123
+ - spec/handlebars_spec.rb
data/README.md DELETED
@@ -1,39 +0,0 @@
1
- Handlebars
2
- ==========
3
-
4
- Handlebars is a implementation of [handlebars.js][2], an extension of
5
- mustache by Yehuda Katz, in Ruby.
6
-
7
-
8
- Current status
9
- --------------
10
-
11
- So far only the parser has been implemented. It supports the whole
12
- handlebars syntax.
13
-
14
-
15
- Installation
16
- ------------
17
-
18
- ### [RubyGems](http://rubygems.org/)
19
-
20
- $ gem install handlebars
21
-
22
-
23
- Acknowledgements
24
- ----------------
25
-
26
- Thanks to all the [implementers][3] of the original mustache gem.
27
- Handlebars is based on their codebase and hard work.
28
-
29
-
30
- Meta
31
- ----
32
-
33
- * Code: `git clone http://github.com/MSch/handlebars-ruby`
34
- * Bugs: <http://github.com/MSch/handlebars-ruby/issues>
35
- * Gems: <http://rubygems.org/gems/handlebars>
36
-
37
- [1]:http://github.com/wycats/handlebars.js
38
- [2]:http://yehudakatz.com/2010/09/09/announcing-handlebars-js/
39
- [3]:http://github.com/defunkt/mustache/raw/master/CONTRIBUTORS
@@ -1,4 +0,0 @@
1
- class Handlebars
2
- class Generator
3
- end
4
- end
@@ -1,240 +0,0 @@
1
- require 'strscan'
2
-
3
- class Handlebars
4
- class Parser
5
- # A SyntaxError is raised when the Parser comes across unclosed
6
- # tags, sections, illegal content in tags, or anything of that
7
- # sort.
8
- class SyntaxError < StandardError
9
- def initialize(message, position)
10
- @message = message
11
- @lineno, @column, @line = position
12
- @stripped_line = @line.strip
13
- @stripped_column = @column - (@line.size - @line.lstrip.size)
14
- end
15
-
16
- def to_s
17
- <<-EOF
18
- #{@message}
19
- Line #{@lineno}
20
- #{@stripped_line}
21
- #{' ' * @stripped_column}^
22
- EOF
23
- end
24
- end
25
-
26
- # After these types of tags, all whitespace will be skipped.
27
- SKIP_WHITESPACE = [ '#', '^', '/' ]
28
-
29
- # The content allowed in a tag name.
30
- ALLOWED_CONTENT = /(\w|[.?!\/-])*/
31
-
32
- # These types of tags allow any content,
33
- # the rest only allow ALLOWED_CONTENT.
34
- ANY_CONTENT = [ '!', '=' ]
35
-
36
- attr_reader :scanner, :result
37
- attr_writer :otag, :ctag
38
-
39
- # Accepts an options hash which does nothing but may be used in
40
- # the future.
41
- def initialize(options = {})
42
- @options = {}
43
- end
44
-
45
- # The opening tag delimiter. This may be changed at runtime.
46
- def otag
47
- @otag ||= '{{'
48
- end
49
-
50
- # The closing tag delimiter. This too may be changed at runtime.
51
- def ctag
52
- @ctag ||= '}}'
53
- end
54
-
55
- # Given a string template, returns an array of tokens.
56
- def compile(template)
57
- if template.respond_to?(:encoding)
58
- @encoding = template.encoding
59
- template = template.dup.force_encoding("BINARY")
60
- else
61
- @encoding = nil
62
- end
63
-
64
- # Keeps information about opened sections.
65
- @sections = []
66
- @result = [:multi]
67
- @scanner = StringScanner.new(template)
68
-
69
- # Scan until the end of the template.
70
- until @scanner.eos?
71
- scan_tags || scan_text
72
- end
73
-
74
- if !@sections.empty?
75
- # We have parsed the whole file, but there's still opened sections.
76
- type, pos, result = @sections.pop
77
- error "Unclosed section #{type.inspect}", pos
78
- end
79
-
80
- @result
81
- end
82
-
83
- # Find {{mustaches}} and add them to the @result array.
84
- def scan_tags
85
- # Scan until we hit an opening delimiter.
86
- return unless @scanner.scan(regexp(otag))
87
-
88
- # Since {{= rewrites ctag, we store the ctag which should be used
89
- # when parsing this specific tag.
90
- current_ctag = self.ctag
91
- type = @scanner.scan(/#|\^|\/|=|!|<|>|&|\{/)
92
- @scanner.skip(/\s*/)
93
-
94
- # ANY_CONTENT tags allow any character inside of them, while
95
- # other tags (such as variables) are more strict.
96
- if ANY_CONTENT.include?(type)
97
- r = /\s*#{regexp(type)}?#{regexp(current_ctag)}/
98
- content = scan_until_exclusive(r)
99
- else
100
- content = @scanner.scan(ALLOWED_CONTENT)
101
- end
102
-
103
- # We found {{ but we can't figure out what's going on inside.
104
- # This applies to all tags except handlebar's shortened {{^}}
105
- if type != '^'
106
- error "Illegal content in tag" if content.empty?
107
- end
108
-
109
- def find_context
110
- # A space after the helper indicates a context 'switch'
111
- if @scanner.peek(1) == ' '
112
- @scanner.skip(/ /)
113
- @scanner.scan(ALLOWED_CONTENT)
114
- else
115
- nil
116
- end
117
- end
118
-
119
- # Based on the sigil, do what needs to be done.
120
- case type
121
- when '#'
122
- block = [:multi]
123
- @result << [:mustache, :section, content, find_context(), block]
124
- @sections << [content, position, @result]
125
- @result = block
126
- when '^'
127
- if content.empty?
128
- # We are dealing with handlebar's shortened {{^}}
129
-
130
- # Close the section
131
- section, pos, result = @sections.pop
132
- @result = result
133
- if section.nil?
134
- error "Inverting unopened section"
135
- end
136
-
137
- # Open a new inverted section with the same name
138
- block = [:multi]
139
- @result << [:mustache, :inverted_section, section, block]
140
- @sections << [section, position, @result]
141
- @result = block
142
- else
143
- block = [:multi]
144
- @result << [:mustache, :inverted_section, content, block]
145
- @sections << [content, position, @result]
146
- @result = block
147
- end
148
- when '/'
149
- section, pos, result = @sections.pop
150
- @result = result
151
-
152
- if section.nil?
153
- error "Closing unopened #{content.inspect}"
154
- elsif section != content
155
- error "Unclosed section #{section.inspect}", pos
156
- end
157
- when '!'
158
- # ignore comments
159
- when '='
160
- self.otag, self.ctag = content.split(' ', 2)
161
- when '>', '<'
162
- @result << [:mustache, :partial, content]
163
- when '{', '&'
164
- # The closing } in unescaped tags is just a hack for
165
- # aesthetics.
166
- type = "}" if type == "{"
167
- @result << [:mustache, :utag, content]
168
- else
169
- @result << [:mustache, :etag, content, find_context()]
170
- end
171
-
172
- # Skip whitespace and any balancing sigils after the content
173
- # inside this tag.
174
- @scanner.skip(/\s+/)
175
- @scanner.skip(regexp(type)) if type
176
-
177
- # Try to find the closing tag.
178
- unless close = @scanner.scan(regexp(current_ctag))
179
- error "Unclosed tag"
180
- end
181
-
182
- # Skip whitespace following this tag if we need to.
183
- @scanner.skip(/\s+/) if SKIP_WHITESPACE.include?(type)
184
- end
185
-
186
- # Try to find static text, e.g. raw HTML with no {{mustaches}}.
187
- def scan_text
188
- text = scan_until_exclusive(regexp(otag))
189
-
190
- if text.nil?
191
- # Couldn't find any otag, which means the rest is just static text.
192
- text = @scanner.rest
193
- # Mark as done.
194
- @scanner.clear
195
- end
196
-
197
- text.force_encoding(@encoding) if @encoding
198
-
199
- @result << [:static, text]
200
- end
201
-
202
- # Scans the string until the pattern is matched. Returns the substring
203
- # *excluding* the end of the match, advancing the scan pointer to that
204
- # location. If there is no match, nil is returned.
205
- def scan_until_exclusive(regexp)
206
- pos = @scanner.pos
207
- if @scanner.scan_until(regexp)
208
- @scanner.pos -= @scanner.matched.size
209
- @scanner.pre_match[pos..-1]
210
- end
211
- end
212
-
213
- # Returns [lineno, column, line]
214
- def position
215
- # The rest of the current line
216
- rest = @scanner.check_until(/\n|\Z/).to_s.chomp
217
-
218
- # What we have parsed so far
219
- parsed = @scanner.string[0...@scanner.pos]
220
-
221
- lines = parsed.split("\n")
222
-
223
- [ lines.size, lines.last.size - 1, lines.last + rest ]
224
- end
225
-
226
- # Used to quickly convert a string into a regular expression
227
- # usable by the string scanner.
228
- def regexp(thing)
229
- /#{Regexp.escape(thing)}/
230
- end
231
-
232
- # Raises a SyntaxError. The message should be the name of the
233
- # error - other details such as line number and position are
234
- # handled for you.
235
- def error(message, pos = position)
236
- raise SyntaxError.new(message, pos)
237
- end
238
- end
239
- end
240
-