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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b98b2000688c656f6b8d50dc7ca337140c0ce108
4
+ data.tar.gz: 56ed522869ab837b945e2859bdfbeedef6f5d1c9
5
+ SHA512:
6
+ metadata.gz: 4f86668e7bdcf4cb162b4b199fb0bd8881e11c675e014df62cbb119f06f25a963a024b8683fa0f8a064fb6ec6f3fa630c43098299fbf9e5768a6ac6e0e021c28
7
+ data.tar.gz: a11b96888f15fb9017427ecffef1a232cce785ad066c7e2c11faf42ce280d23a59d4c4e07c30edce6d2728c51e84f1c765c311d066125ab75b1e7d029ca29729
@@ -0,0 +1,11 @@
1
+ .DS_Store
2
+ /.bundle/
3
+ /.yardoc
4
+ /Gemfile.lock
5
+ /_yardoc/
6
+ /coverage/
7
+ /doc/
8
+ /pkg/
9
+ /spec/reports/
10
+ /tmp/
11
+ bin/pre-commit
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,17 @@
1
+ Metrics/LineLength:
2
+ Max: 120
3
+
4
+ Style/SpaceInsideHashLiteralBraces:
5
+ EnforcedStyle: no_space
6
+
7
+ Metrics/AbcSize:
8
+ Enabled: false
9
+
10
+ Metrics/MethodLength:
11
+ Max: 30
12
+
13
+ Style/DoubleNegation:
14
+ Enabled: false
15
+
16
+ Style/WordArray:
17
+ Enabled: false
@@ -0,0 +1 @@
1
+ 2.3.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in emerald.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Andrew McBurney, Dave Pagurek, Yu Chen Hu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,18 @@
1
+ <img src='emerald-logo.png' alt='Drawing' width='600px' />
2
+ - A language agnostic templating engine designed with event driven applications in mind.
3
+
4
+ # Usage
5
+ ```
6
+ bin/emerald process some_html_file --beautify
7
+ ```
8
+
9
+ # Setup
10
+ ```
11
+ bundle install
12
+ bundle exec rake setup
13
+ ```
14
+
15
+ # Running tests
16
+ ```
17
+ bundle exec rake test
18
+ ```
@@ -0,0 +1,12 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'pre-commit'
4
+
5
+ RSpec::Core::RakeTask.new(:test)
6
+
7
+ task :setup do
8
+ sh 'pre-commit install'
9
+ sh 'git config pre-commit.checks "[rubocop]"'
10
+ end
11
+
12
+ task :default => :test
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "emerald"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
5
+ require 'emerald'
6
+
7
+ Emerald::CLI.start(ARGV)
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,13 @@
1
+ machine:
2
+ ruby:
3
+ version:
4
+ 2.3.2
5
+
6
+ dependencies:
7
+ override:
8
+ - bundle install:
9
+ timeout: 240
10
+
11
+ test:
12
+ override:
13
+ - bundle exec rake test
@@ -0,0 +1,5 @@
1
+ ---
2
+ :checks_add:
3
+ - :rubocop
4
+ :checks_remove:
5
+ - :rails
Binary file
@@ -0,0 +1,33 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'emerald/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'emerald-lang'
8
+ spec.version = Emerald::VERSION
9
+ spec.authors = ['Andrew McBurney', 'Dave Pagurek', 'Yu Chen Hu']
10
+ spec.email = ['andrewrobertmcburney@gmail.com', 'davepagurek@gmail.com', 'me@yuchenhou.com']
11
+
12
+ spec.summary = 'A language agnostic templating engine designed with event driven applications in mind.'
13
+ spec.description = 'A language agnostic templating engine designed with event driven applications in mind.' # TODO: make better description
14
+ spec.homepage = 'https://github.com/emerald-lang/emerald' # TODO: replace with website once created
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = 'bin'
19
+ spec.executables = ['emerald']
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.add_development_dependency 'bundler', '~> 1.10'
23
+ spec.add_development_dependency 'rake', '~> 10.0'
24
+ spec.add_development_dependency 'rspec'
25
+ spec.add_development_dependency 'test-unit'
26
+ spec.add_development_dependency 'rubocop'
27
+ spec.add_development_dependency 'pre-commit'
28
+
29
+ spec.add_runtime_dependency 'htmlentities'
30
+ spec.add_runtime_dependency 'treetop'
31
+ spec.add_runtime_dependency 'thor'
32
+ spec.add_runtime_dependency 'htmlbeautifier', '~> 1.1', '>= 1.1.1'
33
+ end
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # Emerald, the language agnostic templating engine.
6
+ # Copyright 2016, Emerald Language (MIT)
7
+ #
8
+ require 'emerald/version'
9
+
10
+ require 'json'
11
+ require 'thor'
12
+ require 'htmlbeautifier'
13
+
14
+ require_relative 'emerald/grammar'
15
+ require_relative 'emerald/preprocessor'
16
+
17
+ # Parses a context free grammar from the preprocessed emerald and generates
18
+ # html associated with corresponding abstract syntax tree.
19
+ module Emerald
20
+ # The Emerald CLI
21
+ class CLI < Thor
22
+ class_option :beautify, :type => :boolean, :aliases => 'b'
23
+
24
+ def self.exit_on_failure?
25
+ true
26
+ end
27
+
28
+ # Main emerald option, processes the emerald file, generates an abstract
29
+ # syntax tree based on the output from the preprocessing.
30
+ desc 'process', 'Process a file or folder (recursively) and converts it to emerald.'
31
+ option :output, aliases: 'o'
32
+ def process(file_name, context_file_name = nil)
33
+ begin
34
+ output_name = options[:output] || file_name
35
+ context =
36
+ if context_file_name
37
+ JSON.parse(IO.read(context_file_name))
38
+ else
39
+ {}
40
+ end
41
+
42
+ input = IO.read(file_name)
43
+
44
+ Emerald.write_html(
45
+ Emerald.convert(input, context),
46
+ output_name,
47
+ options['beautify']
48
+ )
49
+ rescue Grammar::PreProcessorError, Grammar::ParserError => e
50
+ raise Thor::Error, e.message
51
+ end
52
+ end
53
+ end
54
+
55
+ def self.convert(input, context = {})
56
+ preprocessed_emerald, source_map = PreProcessor.new.process_emerald(input)
57
+ abstract_syntax_tree = Grammar.parse_grammar(
58
+ preprocessed_emerald,
59
+ input,
60
+ source_map
61
+ )
62
+
63
+ return abstract_syntax_tree.to_html(context)
64
+ end
65
+
66
+ # Write html to file and beautify it if the beautify global option is set to
67
+ # true.
68
+ def self.write_html(html_output, file_name, beautify)
69
+ File.open(file_name + '.html', 'w') do |emerald_file|
70
+ html_output = HtmlBeautifier.beautify(html_output) if beautify
71
+ emerald_file.write(html_output)
72
+ end
73
+ puts "Wrote #{file_name + '.html'}"
74
+ end
75
+ end
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'polyglot'
5
+ require 'treetop'
6
+
7
+ # Require all treetop nodes for grammar
8
+ Dir[File.dirname(__FILE__) + '/nodes/*.rb'].each { |f| require f }
9
+
10
+ Treetop.load __dir__ + '/grammar/tokens'
11
+ Treetop.load __dir__ + '/grammar/variables'
12
+ Treetop.load __dir__ + '/grammar/scopes'
13
+ Treetop.load __dir__ + '/grammar/emerald'
14
+
15
+ #
16
+ # Interface which interacts with emerald context free grammar. Parses the
17
+ # preprocessed Emerald and prints out success if the parser was successful and
18
+ # failure if there was an error when parsing. Returns an abstract syntax tree.
19
+ #
20
+ module Grammar
21
+ # When the parser fails on a line from user input
22
+ class ParserError < StandardError
23
+ LINES_BEFORE = 3
24
+ LINES_AFTER = 1
25
+
26
+ def initialize(line_number, reason, source)
27
+ @line_number = line_number
28
+ @reason = reason
29
+ @source = source
30
+ end
31
+
32
+ def message
33
+ messages = []
34
+ if match = @reason.match(/(Expected .+?) at line/)
35
+ messages << match[1]
36
+ else
37
+ messages << @reason
38
+ end
39
+
40
+ lines = @source.split(/\n/)
41
+ LINES_BEFORE.downto(1).each do |i|
42
+ messages << ' ' + lines[@line_number - i - 1] if lines[@line_number - i - 1]
43
+ end
44
+ messages << '>>> ' + lines[@line_number - 1]
45
+ 1.upto(LINES_AFTER).each do |i|
46
+ messages << ' ' + lines[@line_number + i - 1] if lines[@line_number + i - 1]
47
+ end
48
+
49
+ messages.join("\n")
50
+ end
51
+ end
52
+
53
+ # When the parser fails on a line added only in preprocessing
54
+ class PreProcessorError < ParserError
55
+ def say
56
+ messages = []
57
+ messages << "Error parsing in pre-processed Emerald. This is likely a bug."
58
+ messages << @reason
59
+ messages.concat(@source.lines.with_index { |line, i| puts "#{i + 1} #{line}" })
60
+
61
+ messages.join("\n")
62
+ end
63
+ end
64
+
65
+ @parser = EmeraldParser.new
66
+
67
+ # Parse the preprocessed emerald text and print failure if it fails the
68
+ # parsing stage
69
+ def self.parse_grammar(text, original, source_map)
70
+ parsed = @parser.parse(text)
71
+
72
+ if parsed.nil?
73
+ source_line = source_map[@parser.failure_line][:source_line]
74
+ if source_line.nil?
75
+ raise PreProcessorError.new(
76
+ @parser.failure_line,
77
+ @parser.failure_reason,
78
+ text
79
+ )
80
+ end
81
+ raise ParserError.new(
82
+ source_line,
83
+ @parser.failure_reason,
84
+ original
85
+ )
86
+ end
87
+
88
+ parsed
89
+ end
90
+ end
@@ -0,0 +1,93 @@
1
+ #
2
+ # Context free grammar for the Emerald language.
3
+ # Emerald: a preprocessor for html5.
4
+ #
5
+ grammar Emerald
6
+ include Tokens
7
+ include Scopes
8
+ include Variables
9
+
10
+ rule main
11
+ (scope / pair_list / value_list / nested / line / comment)+ <Root>
12
+ end
13
+
14
+ rule nested
15
+ tag_statement newline lbrace newline main rbrace newline <Nested>
16
+ end
17
+
18
+ rule scope
19
+ fn:scope_fn lbrace newline body:main rbrace newline <Scope>
20
+ end
21
+
22
+ rule line
23
+ (tag_statement / comment) newline <Line>
24
+ end
25
+
26
+ rule value_list
27
+ keyword:special_keyword newline lbrace newline
28
+ list_items:(literal:inline_literal_string newline)+
29
+ rbrace newline <ValueList>
30
+ end
31
+
32
+ rule pair_list
33
+ keyword:base_keyword newline lbrace newline
34
+ list_items:(pairs:(attr:attr space+ literal:inline_literal_string space*)+ newline)+
35
+ rbrace newline <PairList>
36
+ end
37
+
38
+ rule comment
39
+ space* '*' space* text_content <Comment>
40
+ end
41
+
42
+ rule text_content
43
+ multiline_literal / multiline_templateless_literal / inline_literal
44
+ end
45
+
46
+ rule multiline_literal
47
+ "->" space* newline
48
+ body:(variable / escaped / !'$' .)*
49
+ "$" <TextLiteral>
50
+ end
51
+
52
+ rule multiline_templateless_literal
53
+ ("=>" / "~>") space* newline
54
+ body:(escaped / !'$' .)*
55
+ "$" <TextLiteral>
56
+ end
57
+
58
+ rule inline_literal
59
+ body:( variable / escaped / !lparen !newline . )* <TextLiteral>
60
+ end
61
+
62
+ rule inline_literal_string
63
+ '"' body:( variable / escaped / !'"' . )* '"' <TextLiteral>
64
+ end
65
+
66
+ rule escaped
67
+ "\\" .
68
+ end
69
+
70
+ rule tag_statement
71
+ tag identifier:id_name? classes:class_name* space* body:text_content? attributes:attr_list? <TagStatement>
72
+ end
73
+
74
+ rule id_name
75
+ '#' name:([a-zA-Z_\-]+)
76
+ end
77
+
78
+ rule class_name
79
+ '.' name:([a-zA-Z_\-]+)
80
+ end
81
+
82
+ rule attr_list
83
+ lparen newline lbrace newline attributes rbrace newline rparen <AttributeList>
84
+ end
85
+
86
+ rule attributes
87
+ attribute* <Attributes>
88
+ end
89
+
90
+ rule attribute
91
+ attr space* inline_literal_string newline
92
+ end
93
+ end