emerald-lang 1.0.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.
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: []