reco 0.1.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/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
@@ -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
@@ -0,0 +1,11 @@
1
+ module Reco
2
+ VERSION = '0.1.0'
3
+
4
+ autoload :Compiler, "reco/compiler"
5
+ autoload :Scanner, "reco/scanner"
6
+ autoload :Preprocessor, "reco/preprocessor"
7
+
8
+ def self.compile(source, options = {})
9
+ Compiler.compile source, options
10
+ end
11
+ end
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
+