emerald-lang 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +17 -0
  5. data/.ruby-version +1 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +18 -0
  9. data/Rakefile +12 -0
  10. data/bin/console +14 -0
  11. data/bin/emerald +7 -0
  12. data/bin/setup +7 -0
  13. data/circle.yml +13 -0
  14. data/config/pre_commit.yml +5 -0
  15. data/emerald-logo.png +0 -0
  16. data/emerald.gemspec +33 -0
  17. data/lib/emerald.rb +75 -0
  18. data/lib/emerald/grammar.rb +90 -0
  19. data/lib/emerald/grammar/emerald.tt +93 -0
  20. data/lib/emerald/grammar/scopes.tt +48 -0
  21. data/lib/emerald/grammar/tokens.tt +57 -0
  22. data/lib/emerald/grammar/variables.tt +10 -0
  23. data/lib/emerald/index.emr +33 -0
  24. data/lib/emerald/nodes/attribute_list.rb +13 -0
  25. data/lib/emerald/nodes/attributes.rb +16 -0
  26. data/lib/emerald/nodes/base_scope_fn.rb +11 -0
  27. data/lib/emerald/nodes/binary_expr.rb +17 -0
  28. data/lib/emerald/nodes/boolean_expr.rb +11 -0
  29. data/lib/emerald/nodes/comment.rb +12 -0
  30. data/lib/emerald/nodes/each.rb +40 -0
  31. data/lib/emerald/nodes/given.rb +16 -0
  32. data/lib/emerald/nodes/line.rb +13 -0
  33. data/lib/emerald/nodes/nested.rb +17 -0
  34. data/lib/emerald/nodes/node.rb +11 -0
  35. data/lib/emerald/nodes/pair_list.rb +23 -0
  36. data/lib/emerald/nodes/root.rb +14 -0
  37. data/lib/emerald/nodes/scope.rb +12 -0
  38. data/lib/emerald/nodes/scope_fn.rb +12 -0
  39. data/lib/emerald/nodes/tag_statement.rb +78 -0
  40. data/lib/emerald/nodes/text_literal.rb +26 -0
  41. data/lib/emerald/nodes/unary_expr.rb +16 -0
  42. data/lib/emerald/nodes/unless.rb +16 -0
  43. data/lib/emerald/nodes/value_list.rb +18 -0
  44. data/lib/emerald/nodes/variable.rb +14 -0
  45. data/lib/emerald/nodes/variable_name.rb +21 -0
  46. data/lib/emerald/nodes/with.rb +14 -0
  47. data/lib/emerald/preprocessor.rb +145 -0
  48. data/lib/emerald/version.rb +3 -0
  49. data/sample.emr +45 -0
  50. metadata +245 -0
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'treetop'
5
+ require_relative 'node'
6
+
7
+ # A long block of text literal, with variable templating
8
+ class TextLiteral < Node
9
+ def to_html(context)
10
+ body
11
+ .elements
12
+ .map do |element|
13
+ if element.is_a?(Variable)
14
+ element.to_html(context)
15
+ else
16
+ unescape element.text_value
17
+ end
18
+ end
19
+ .join('')
20
+ .rstrip
21
+ end
22
+
23
+ def unescape(text)
24
+ text.gsub(/\\(.)/, '\1')
25
+ end
26
+ end
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'treetop'
5
+ require_relative 'boolean_expr'
6
+
7
+ # A boolean expression with one child
8
+ class UnaryExpr < BooleanExpr
9
+ def truthy?(context)
10
+ if negated.text_value.length.positive?
11
+ !elements[1].val.truthy?(context)
12
+ else
13
+ elements[1].val.truthy?(context)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'treetop'
5
+ require_relative 'base_scope_fn'
6
+
7
+ # Renders unless a condition is met
8
+ class Unless < BaseScopeFn
9
+ def to_html(body, context)
10
+ if boolean_expr.truthy?(context)
11
+ ''
12
+ else
13
+ body.to_html(context)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'treetop'
5
+ require_relative 'node'
6
+
7
+ # Special rule for lists of images, styles, and scripts
8
+ class ValueList < Node
9
+ def to_html(context)
10
+ list_items.elements.map do |e|
11
+ case keyword.text_value
12
+ when 'images' then "<img src=\"#{e.literal.to_html(context)}\"/>"
13
+ when 'styles' then "<link rel=\"stylesheet\" href=\"#{e.literal.to_html(context)}\"/>"
14
+ when 'scripts' then "<script type=\"text/javascript\" src=\"#{e.literal.to_html(context)}\"></script>"
15
+ end
16
+ end.join("\n")
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'treetop'
5
+ require_relative 'node'
6
+
7
+ # Variable interpolation in a template
8
+ class Variable < Node
9
+ def to_html(context)
10
+ variable_name
11
+ .content(context)
12
+ .to_s
13
+ end
14
+ end
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'treetop'
5
+ require_relative 'boolean_expr'
6
+
7
+ # Variable interpolation in a template
8
+ class VariableName < BooleanExpr
9
+ def content(context)
10
+ text_value
11
+ .split('.')
12
+ .reduce(context) do |ctx, name|
13
+ next nil if ctx.nil?
14
+ ctx[name] || ctx[name.to_sym] || nil
15
+ end
16
+ end
17
+
18
+ def truthy?(context)
19
+ !!content(context)
20
+ end
21
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'treetop'
5
+ require_relative 'base_scope_fn'
6
+
7
+ # Isolates the scope to a subset of the context
8
+ class With < BaseScopeFn
9
+ def to_html(body, context)
10
+ var = elements[2].content(context)
11
+
12
+ body.to_html(var)
13
+ end
14
+ end
@@ -0,0 +1,145 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'htmlentities'
5
+ require_relative 'grammar'
6
+
7
+ module Emerald
8
+ #
9
+ # Preprocess the emerald code and add notion of indentation so it may be parsed
10
+ # by a context free grammar. Removes all whitespace and adds braces to denote
11
+ # indentation.
12
+ #
13
+ class PreProcessor
14
+ def initialize
15
+ reset
16
+ end
17
+
18
+ # Reset class variables, used for testing
19
+ def reset
20
+ @in_literal = false
21
+ @templateless_literal = false
22
+ @current_indent = 0
23
+ @b_count = 0
24
+ @output = ''
25
+ @encoder = HTMLEntities.new
26
+ @source_map = {}
27
+ end
28
+
29
+ # Process the emerald to remove indentation and replace with brace convention
30
+ # for an easier time parsing with context free grammar
31
+ def process_emerald(input)
32
+ input.each_line.with_index do |line, line_number|
33
+ if @in_literal
34
+ if line[0...-1].empty?
35
+ new_indent = @current_indent
36
+ line = " "*@current_indent + "\n"
37
+ else
38
+ new_indent = line.length - line.lstrip.length
39
+ end
40
+ else
41
+ next if line.lstrip.empty?
42
+ new_indent = line.length - line.lstrip.length
43
+ end
44
+
45
+ check_new_indent(new_indent)
46
+ @output += remove_indent_whitespace(line)
47
+ @source_map[@output.lines.length] = {
48
+ source_line: line_number + 1
49
+ }
50
+ check_and_enter_literal(line)
51
+ end
52
+
53
+ close_tags(0)
54
+
55
+ [@output, @source_map]
56
+ end
57
+
58
+ # Compares the value of the new_indent with the old indentation.
59
+ # Invoked by: process_emerald
60
+ def check_new_indent(new_indent)
61
+ if new_indent > @current_indent
62
+ open_tags(new_indent)
63
+ elsif new_indent < @current_indent
64
+ close_tags(new_indent)
65
+ end
66
+ end
67
+
68
+ def open_tags(new_indent)
69
+ return if @in_literal
70
+ @output += "{\n"
71
+ @b_count += 1
72
+ @current_indent = new_indent
73
+ end
74
+
75
+ def close_tags(new_indent)
76
+ if @in_literal
77
+ close_literal(new_indent)
78
+ else
79
+ close_entered_tags(new_indent)
80
+ end
81
+ @current_indent = new_indent
82
+ end
83
+
84
+ # Append closing braces if in literal and new indent is less than old one
85
+ def close_literal(new_indent)
86
+ @output += "$\n"
87
+ @in_literal = false
88
+
89
+ (2..((@current_indent - new_indent) / 2)).each do
90
+ @output += "}\n"
91
+ @b_count -= 1
92
+ end
93
+ end
94
+
95
+ # Append closing braces if not in literal and new indent is less than old one
96
+ def close_entered_tags(new_indent)
97
+ (1..((@current_indent - new_indent) / 2)).each do
98
+ @output += "}\n"
99
+ @b_count -= 1
100
+ end
101
+ end
102
+
103
+ # Crop off only Emerald indent whitespace to preserve whitespace in the
104
+ # literal. Since $ is the end character, we need to escape it in the literal.
105
+ def remove_indent_whitespace(line)
106
+ if @in_literal
107
+ # Ignore indent whitespace, only count post-indent as the literal,
108
+ # but keep any extra whitespace that might exist for literals
109
+ cropped = line[@current_indent..-1] || ''
110
+ if @templateless_literal
111
+ # this is a fun one https://www.ruby-forum.com/topic/143645
112
+ cropped = cropped.gsub("\\"){ "\\\\" }
113
+ end
114
+
115
+ unless @preserve_html_literal
116
+ cropped = @encoder.encode cropped
117
+ end
118
+
119
+ # Escape $ since we use it as a terminator for literals, and encode HTML
120
+ cropped.gsub('$', "\\$")
121
+ else
122
+ line.lstrip
123
+ end
124
+ end
125
+
126
+ def check_and_enter_literal(line)
127
+ if line.rstrip.end_with?('->')
128
+ @in_literal = true
129
+ @current_indent += 2
130
+ @templateless_literal = false
131
+ @preserve_html_literal = false
132
+ elsif line.rstrip.end_with?('=>')
133
+ @in_literal = true
134
+ @current_indent += 2
135
+ @templateless_literal = true
136
+ @preserve_html_literal = false
137
+ elsif line.rstrip.end_with?('~>')
138
+ @in_literal = true
139
+ @current_indent += 2
140
+ @templateless_literal = true
141
+ @preserve_html_literal = true
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,3 @@
1
+ module Emerald
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,45 @@
1
+ * Emerald Language
2
+
3
+ doctype html
4
+
5
+ html
6
+ head
7
+ styles
8
+ "css/main.css"
9
+ "css/vendor/bootstrap.min.css"
10
+
11
+ scripts
12
+ "js/script.js"
13
+ "js/other_script.js"
14
+
15
+ style
16
+ var black = #333
17
+ var blue = #0066ff
18
+
19
+ body
20
+ header
21
+ h1 Emerald
22
+ h2 An html5 markup language designed with event driven
23
+ applications in mind.
24
+
25
+ main
26
+ section
27
+ h1 Why use Emerald?
28
+ p Emerald allows you to scope events and styles to html
29
+ elements in an elegant, clean way.
30
+
31
+ figure
32
+ figcaption Here's an example of elements scoped in a
33
+ button here.
34
+
35
+ button Click me. (
36
+ click -> console.log("I was clicked!")
37
+ hover -> console.log("I was hovered!")
38
+ )
39
+
40
+ footer (
41
+ hover ->
42
+ this.border = 1px solid @blue
43
+ this.text-shadow = 0px 0px 8px 2px rgba(0,0,0,0.3)
44
+ )
45
+ p Like what you see? Check out the docs for more samples.
metadata ADDED
@@ -0,0 +1,245 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: emerald-lang
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Andrew McBurney
8
+ - Dave Pagurek
9
+ - Yu Chen Hu
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2017-01-10 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: bundler
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - "~>"
20
+ - !ruby/object:Gem::Version
21
+ version: '1.10'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - "~>"
27
+ - !ruby/object:Gem::Version
28
+ version: '1.10'
29
+ - !ruby/object:Gem::Dependency
30
+ name: rake
31
+ requirement: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - "~>"
34
+ - !ruby/object:Gem::Version
35
+ version: '10.0'
36
+ type: :development
37
+ prerelease: false
38
+ version_requirements: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - "~>"
41
+ - !ruby/object:Gem::Version
42
+ version: '10.0'
43
+ - !ruby/object:Gem::Dependency
44
+ name: rspec
45
+ requirement: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ type: :development
51
+ prerelease: false
52
+ version_requirements: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ - !ruby/object:Gem::Dependency
58
+ name: test-unit
59
+ requirement: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ type: :development
65
+ prerelease: false
66
+ version_requirements: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ - !ruby/object:Gem::Dependency
72
+ name: rubocop
73
+ requirement: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ type: :development
79
+ prerelease: false
80
+ version_requirements: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ - !ruby/object:Gem::Dependency
86
+ name: pre-commit
87
+ requirement: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ type: :development
93
+ prerelease: false
94
+ version_requirements: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ - !ruby/object:Gem::Dependency
100
+ name: htmlentities
101
+ requirement: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ type: :runtime
107
+ prerelease: false
108
+ version_requirements: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ - !ruby/object:Gem::Dependency
114
+ name: treetop
115
+ requirement: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ type: :runtime
121
+ prerelease: false
122
+ version_requirements: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ - !ruby/object:Gem::Dependency
128
+ name: thor
129
+ requirement: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ type: :runtime
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
141
+ - !ruby/object:Gem::Dependency
142
+ name: htmlbeautifier
143
+ requirement: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - "~>"
146
+ - !ruby/object:Gem::Version
147
+ version: '1.1'
148
+ - - ">="
149
+ - !ruby/object:Gem::Version
150
+ version: 1.1.1
151
+ type: :runtime
152
+ prerelease: false
153
+ version_requirements: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - "~>"
156
+ - !ruby/object:Gem::Version
157
+ version: '1.1'
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ version: 1.1.1
161
+ description: A language agnostic templating engine designed with event driven applications
162
+ in mind.
163
+ email:
164
+ - andrewrobertmcburney@gmail.com
165
+ - davepagurek@gmail.com
166
+ - me@yuchenhou.com
167
+ executables:
168
+ - emerald
169
+ extensions: []
170
+ extra_rdoc_files: []
171
+ files:
172
+ - ".gitignore"
173
+ - ".rspec"
174
+ - ".rubocop.yml"
175
+ - ".ruby-version"
176
+ - Gemfile
177
+ - LICENSE.txt
178
+ - README.md
179
+ - Rakefile
180
+ - bin/console
181
+ - bin/emerald
182
+ - bin/setup
183
+ - circle.yml
184
+ - config/pre_commit.yml
185
+ - emerald-logo.png
186
+ - emerald.gemspec
187
+ - lib/emerald.rb
188
+ - lib/emerald/grammar.rb
189
+ - lib/emerald/grammar/emerald.tt
190
+ - lib/emerald/grammar/scopes.tt
191
+ - lib/emerald/grammar/tokens.tt
192
+ - lib/emerald/grammar/variables.tt
193
+ - lib/emerald/index.emr
194
+ - lib/emerald/nodes/attribute_list.rb
195
+ - lib/emerald/nodes/attributes.rb
196
+ - lib/emerald/nodes/base_scope_fn.rb
197
+ - lib/emerald/nodes/binary_expr.rb
198
+ - lib/emerald/nodes/boolean_expr.rb
199
+ - lib/emerald/nodes/comment.rb
200
+ - lib/emerald/nodes/each.rb
201
+ - lib/emerald/nodes/given.rb
202
+ - lib/emerald/nodes/line.rb
203
+ - lib/emerald/nodes/nested.rb
204
+ - lib/emerald/nodes/node.rb
205
+ - lib/emerald/nodes/pair_list.rb
206
+ - lib/emerald/nodes/root.rb
207
+ - lib/emerald/nodes/scope.rb
208
+ - lib/emerald/nodes/scope_fn.rb
209
+ - lib/emerald/nodes/tag_statement.rb
210
+ - lib/emerald/nodes/text_literal.rb
211
+ - lib/emerald/nodes/unary_expr.rb
212
+ - lib/emerald/nodes/unless.rb
213
+ - lib/emerald/nodes/value_list.rb
214
+ - lib/emerald/nodes/variable.rb
215
+ - lib/emerald/nodes/variable_name.rb
216
+ - lib/emerald/nodes/with.rb
217
+ - lib/emerald/preprocessor.rb
218
+ - lib/emerald/version.rb
219
+ - sample.emr
220
+ homepage: https://github.com/emerald-lang/emerald
221
+ licenses:
222
+ - MIT
223
+ metadata: {}
224
+ post_install_message:
225
+ rdoc_options: []
226
+ require_paths:
227
+ - lib
228
+ required_ruby_version: !ruby/object:Gem::Requirement
229
+ requirements:
230
+ - - ">="
231
+ - !ruby/object:Gem::Version
232
+ version: '0'
233
+ required_rubygems_version: !ruby/object:Gem::Requirement
234
+ requirements:
235
+ - - ">="
236
+ - !ruby/object:Gem::Version
237
+ version: '0'
238
+ requirements: []
239
+ rubyforge_project:
240
+ rubygems_version: 2.5.2
241
+ signing_key:
242
+ specification_version: 4
243
+ summary: A language agnostic templating engine designed with event driven applications
244
+ in mind.
245
+ test_files: []