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.
- data/.gitignore +1 -1
- data/.gitmodules +3 -0
- data/.rspec +1 -0
- data/Gemfile +1 -1
- data/README.mdown +44 -0
- data/Rakefile +3 -0
- data/handlebars.gemspec +19 -13
- data/lib/handlebars.rb +4 -3
- data/lib/handlebars/context.rb +37 -0
- data/lib/handlebars/version.rb +1 -1
- data/spec/handlebars_spec.rb +40 -0
- data/spike.rb +17 -0
- data/vendor/handlebars/.gitignore +6 -0
- data/vendor/handlebars/.jshintrc +50 -0
- data/vendor/handlebars/.npmignore +11 -0
- data/vendor/handlebars/Gemfile +5 -0
- data/vendor/handlebars/LICENSE +20 -0
- data/vendor/handlebars/README.markdown +315 -0
- data/vendor/handlebars/Rakefile +116 -0
- data/vendor/handlebars/bench/benchwarmer.js +149 -0
- data/vendor/handlebars/bench/handlebars.js +163 -0
- data/vendor/handlebars/bin/handlebars +139 -0
- data/vendor/handlebars/lib/handlebars.js +14 -0
- data/vendor/handlebars/lib/handlebars/base.js +101 -0
- data/vendor/handlebars/lib/handlebars/compiler/ast.js +103 -0
- data/vendor/handlebars/lib/handlebars/compiler/base.js +27 -0
- data/vendor/handlebars/lib/handlebars/compiler/compiler.js +808 -0
- data/vendor/handlebars/lib/handlebars/compiler/index.js +7 -0
- data/vendor/handlebars/lib/handlebars/compiler/printer.js +137 -0
- data/vendor/handlebars/lib/handlebars/compiler/visitor.js +13 -0
- data/vendor/handlebars/lib/handlebars/runtime.js +68 -0
- data/vendor/handlebars/lib/handlebars/utils.js +68 -0
- data/vendor/handlebars/package.json +25 -0
- data/vendor/handlebars/spec/acceptance_spec.rb +101 -0
- data/vendor/handlebars/spec/parser_spec.rb +264 -0
- data/vendor/handlebars/spec/qunit_spec.js +1067 -0
- data/vendor/handlebars/spec/spec_helper.rb +157 -0
- data/vendor/handlebars/spec/tokenizer_spec.rb +254 -0
- data/vendor/handlebars/src/handlebars.l +42 -0
- data/vendor/handlebars/src/handlebars.yy +99 -0
- metadata +93 -77
- data/README.md +0 -39
- data/lib/handlebars/generator.rb +0 -4
- data/lib/handlebars/parser.rb +0 -240
- data/spec/generator_spec.rb +0 -5
- data/spec/parser_spec.rb +0 -163
- 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
|
-
|
5
|
-
|
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
|
-
-
|
7
|
+
authors:
|
8
|
+
- Charles Lowell
|
13
9
|
autorequire:
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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
|
-
|
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
|
-
|
29
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
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.
|
60
|
+
- README.mdown
|
63
61
|
- Rakefile
|
64
62
|
- handlebars.gemspec
|
65
63
|
- lib/handlebars.rb
|
66
|
-
- lib/handlebars/
|
67
|
-
- lib/handlebars/parser.rb
|
64
|
+
- lib/handlebars/context.rb
|
68
65
|
- lib/handlebars/version.rb
|
69
|
-
- spec/
|
70
|
-
-
|
71
|
-
-
|
72
|
-
|
73
|
-
|
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
|
-
|
87
|
-
|
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
|
-
|
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.
|
118
|
+
rubygems_version: 1.8.17
|
103
119
|
signing_key:
|
104
120
|
specification_version: 3
|
105
|
-
summary: handlebars.js
|
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
|
data/lib/handlebars/generator.rb
DELETED
data/lib/handlebars/parser.rb
DELETED
@@ -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
|
-
|