reco 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.md +8 -0
- data/lib/reco/compiler.rb +22 -0
- data/lib/reco/preprocessor.rb +71 -0
- data/lib/reco/scanner.rb +87 -0
- data/lib/reco/util.rb +24 -0
- data/lib/reco.rb +11 -0
- metadata +72 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Rasmus Rønn Nielsen
|
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,8 @@
|
|
1
|
+
Reco: Ruby port of the Eco template compiler.
|
2
|
+
=============================================
|
3
|
+
|
4
|
+
Eco is a wonderful javascript template system by [Sam Stephenson](http://twitter.com/sstephenson/). For more information about eco visit [its github page](https://github.com/sstephenson/eco).
|
5
|
+
|
6
|
+
Reco let you compile Eco templates into Javascript through Ruby like this:
|
7
|
+
|
8
|
+
javascript = Reco.compile File.read('some_template')
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'coffee-script'
|
2
|
+
|
3
|
+
module Reco
|
4
|
+
class Compiler
|
5
|
+
def self.preprocess(source)
|
6
|
+
Preprocessor.preprocess source
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.compile(source, options = {})
|
10
|
+
compiled_javascript = CoffeeScript.compile preprocess(source), noWrap: true
|
11
|
+
identifier = options[:identifier] || 'module.exports'
|
12
|
+
identifier = "var #{identifier}" unless identifier.include? '.'
|
13
|
+
|
14
|
+
wrapper % { compiled_javascript: compiled_javascript, identifier: identifier }
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.wrapper
|
18
|
+
File.read File.join(File.dirname(__FILE__), 'wrapper.js')
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'reco/scanner'
|
2
|
+
require 'reco/util'
|
3
|
+
|
4
|
+
module Reco
|
5
|
+
class Preprocessor
|
6
|
+
def self.preprocess(source)
|
7
|
+
new(source).execute
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(source)
|
11
|
+
@scanner = Scanner.new source
|
12
|
+
@output = ''
|
13
|
+
@level = 0
|
14
|
+
@options = {}
|
15
|
+
@captures = []
|
16
|
+
end
|
17
|
+
|
18
|
+
def execute
|
19
|
+
@scanner.scan { |token| send token.shift, *token } until @scanner.done?
|
20
|
+
@output
|
21
|
+
end
|
22
|
+
|
23
|
+
def record(line)
|
24
|
+
@output += @level.times.collect { " " }.join
|
25
|
+
@output += "#{line}\n"
|
26
|
+
end
|
27
|
+
|
28
|
+
def print_string(string)
|
29
|
+
record "__out.push #{Reco::Util.inspect_string(string)}" unless string.empty?
|
30
|
+
end
|
31
|
+
|
32
|
+
def begin_code(options)
|
33
|
+
@options = options
|
34
|
+
end
|
35
|
+
|
36
|
+
def record_code(code)
|
37
|
+
if code != 'end'
|
38
|
+
if @options[:print]
|
39
|
+
record @options[:safe] ? "__out.push #{code}" : "__out.push __sanitize #{code}"
|
40
|
+
else
|
41
|
+
record code
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def indent(capture = nil)
|
47
|
+
@level += 1
|
48
|
+
if capture
|
49
|
+
record "__capture #{capture}"
|
50
|
+
@captures.unshift @level
|
51
|
+
indent
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def dedent
|
56
|
+
@level -= 1
|
57
|
+
fail "unexpected dedent" if @level < 0
|
58
|
+
if @captures[0] == @level
|
59
|
+
@captures.shift
|
60
|
+
dedent
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def fail(message)
|
65
|
+
raise Error, message
|
66
|
+
end
|
67
|
+
|
68
|
+
class Error < Exception; end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
data/lib/reco/scanner.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'strscan'
|
2
|
+
|
3
|
+
class Reco::Scanner
|
4
|
+
MODE_PATTERNS = {
|
5
|
+
data: /(.*?)(<%%|<%(([=-])?)|\n|$)/,
|
6
|
+
code: /(.*?)(((:|(->|=>))\s*)?%>|\n|$)/
|
7
|
+
}
|
8
|
+
DEDENTABLE_PATTERN = /^(end|when|else|catch|finally)(?:\W|$)/
|
9
|
+
|
10
|
+
def self.scan(source)
|
11
|
+
tokens = []
|
12
|
+
scanner = new source
|
13
|
+
scanner.scan { |token| tokens << token } until scanner.done?
|
14
|
+
tokens
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(source)
|
18
|
+
@source = source
|
19
|
+
@scanner = StringScanner.new source
|
20
|
+
@mode = :data
|
21
|
+
@buffer = ''
|
22
|
+
@done = false
|
23
|
+
end
|
24
|
+
|
25
|
+
def scan(callback = nil, &block)
|
26
|
+
callback ||= block
|
27
|
+
|
28
|
+
if @scanner.eos?
|
29
|
+
@done = true
|
30
|
+
callback.call @mode == :data ? ["print_string", flush] : ["fail", "unexpected end of template"]
|
31
|
+
else
|
32
|
+
advance
|
33
|
+
@mode == :data ? scan_data(callback) : scan_code(callback)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def advance
|
38
|
+
@scanner.scan_until MODE_PATTERNS[@mode]
|
39
|
+
@buffer += @scanner[1]
|
40
|
+
@tail = @scanner[2]
|
41
|
+
@directive = @scanner[4]
|
42
|
+
@arrow = @scanner[5]
|
43
|
+
end
|
44
|
+
|
45
|
+
def scan_data(callback)
|
46
|
+
if @tail == "<%%"
|
47
|
+
@buffer += "<%"
|
48
|
+
scan callback
|
49
|
+
elsif @tail == "\n"
|
50
|
+
@buffer += @tail
|
51
|
+
scan callback
|
52
|
+
elsif @tail
|
53
|
+
@mode = :code
|
54
|
+
callback.call ["print_string", flush]
|
55
|
+
callback.call ["begin_code", print: !!@directive, safe: @directive == '-']
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def scan_code(callback)
|
60
|
+
if @tail == "\n"
|
61
|
+
callback.call ["fail", "unexpected newline in code block"]
|
62
|
+
elsif !@tail.empty?
|
63
|
+
@mode = :data
|
64
|
+
code = flush.strip
|
65
|
+
code += " #{@arrow}" if @arrow
|
66
|
+
|
67
|
+
callback.call ["dedent"] if is_dedentable?(code)
|
68
|
+
callback.call ["record_code", code]
|
69
|
+
callback.call ["indent", @arrow] if @directive
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def is_dedentable?(code)
|
74
|
+
code.match DEDENTABLE_PATTERN
|
75
|
+
end
|
76
|
+
|
77
|
+
def flush
|
78
|
+
buffer = @buffer
|
79
|
+
@buffer = ''
|
80
|
+
buffer
|
81
|
+
end
|
82
|
+
|
83
|
+
def done?
|
84
|
+
@done
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
data/lib/reco/util.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
module Reco::Util
|
2
|
+
SPECIAL_CHARACTERS = {
|
3
|
+
"\\" => '\\\\',
|
4
|
+
"\b" => '\\b',
|
5
|
+
"\f" => '\\f',
|
6
|
+
"\n" => '\\n',
|
7
|
+
"\r" => '\\r',
|
8
|
+
"\t" => '\\t'
|
9
|
+
}
|
10
|
+
|
11
|
+
def self.inspect_string(string)
|
12
|
+
string.gsub!(/[\x00-\x1f\\]/) do |character|
|
13
|
+
if SPECIAL_CHARACTERS[character]
|
14
|
+
SPECIAL_CHARACTERS[character]
|
15
|
+
else
|
16
|
+
code = character.ord.to_s 16
|
17
|
+
code = "0#{code}" if code.length == 1
|
18
|
+
"\\u00#{code}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
"'" + string.gsub("'", "\\\\'") + "'"
|
23
|
+
end
|
24
|
+
end
|
data/lib/reco.rb
ADDED
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: reco
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.0
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- "Rasmus R\xC3\xB8nn Nielsen"
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-05-24 00:00:00 +02:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: coffee-script
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ~>
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: "2.0"
|
25
|
+
type: :runtime
|
26
|
+
version_requirements: *id001
|
27
|
+
description: Reco let you compile Eco templates into Javascript through Ruby.
|
28
|
+
email: rasmusrnielsen@gmail.com
|
29
|
+
executables: []
|
30
|
+
|
31
|
+
extensions: []
|
32
|
+
|
33
|
+
extra_rdoc_files: []
|
34
|
+
|
35
|
+
files:
|
36
|
+
- README.md
|
37
|
+
- LICENSE
|
38
|
+
- lib/reco/compiler.rb
|
39
|
+
- lib/reco/preprocessor.rb
|
40
|
+
- lib/reco/scanner.rb
|
41
|
+
- lib/reco/util.rb
|
42
|
+
- lib/reco.rb
|
43
|
+
has_rdoc: true
|
44
|
+
homepage: https://github.com/rasmusrn/reco
|
45
|
+
licenses: []
|
46
|
+
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options: []
|
49
|
+
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
requirements: []
|
65
|
+
|
66
|
+
rubyforge_project:
|
67
|
+
rubygems_version: 1.6.2
|
68
|
+
signing_key:
|
69
|
+
specification_version: 3
|
70
|
+
summary: Ruby port of the Eco template compiler.
|
71
|
+
test_files: []
|
72
|
+
|