reco 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+