faml 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (140) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.gitmodules +3 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +27 -0
  6. data/Appraisals +26 -0
  7. data/CHANGELOG.md +47 -0
  8. data/Gemfile +8 -0
  9. data/LICENSE.txt +22 -0
  10. data/README.md +115 -0
  11. data/Rakefile +28 -0
  12. data/benchmark/attribute_builder.haml +5 -0
  13. data/benchmark/rendering.rb +35 -0
  14. data/bin/faml +4 -0
  15. data/ext/attribute_builder/attribute_builder.c +261 -0
  16. data/ext/attribute_builder/extconf.rb +3 -0
  17. data/faml.gemspec +38 -0
  18. data/gemfiles/rails_4.0.gemfile +9 -0
  19. data/gemfiles/rails_4.1.gemfile +9 -0
  20. data/gemfiles/rails_4.2.gemfile +9 -0
  21. data/gemfiles/rails_edge.gemfile +10 -0
  22. data/haml_spec_test.rb +22 -0
  23. data/lib/faml.rb +10 -0
  24. data/lib/faml/ast.rb +112 -0
  25. data/lib/faml/cli.rb +38 -0
  26. data/lib/faml/compiler.rb +374 -0
  27. data/lib/faml/element_parser.rb +235 -0
  28. data/lib/faml/engine.rb +34 -0
  29. data/lib/faml/filter_compilers.rb +41 -0
  30. data/lib/faml/filter_compilers/base.rb +43 -0
  31. data/lib/faml/filter_compilers/cdata.rb +15 -0
  32. data/lib/faml/filter_compilers/coffee.rb +16 -0
  33. data/lib/faml/filter_compilers/css.rb +16 -0
  34. data/lib/faml/filter_compilers/escaped.rb +23 -0
  35. data/lib/faml/filter_compilers/javascript.rb +16 -0
  36. data/lib/faml/filter_compilers/markdown.rb +18 -0
  37. data/lib/faml/filter_compilers/plain.rb +15 -0
  38. data/lib/faml/filter_compilers/preserve.rb +26 -0
  39. data/lib/faml/filter_compilers/ruby.rb +17 -0
  40. data/lib/faml/filter_compilers/sass.rb +15 -0
  41. data/lib/faml/filter_compilers/scss.rb +16 -0
  42. data/lib/faml/filter_compilers/tilt_base.rb +34 -0
  43. data/lib/faml/filter_parser.rb +54 -0
  44. data/lib/faml/html.rb +58 -0
  45. data/lib/faml/indent_tracker.rb +84 -0
  46. data/lib/faml/line_parser.rb +66 -0
  47. data/lib/faml/newline.rb +30 -0
  48. data/lib/faml/parser.rb +211 -0
  49. data/lib/faml/parser_utils.rb +17 -0
  50. data/lib/faml/rails_handler.rb +10 -0
  51. data/lib/faml/railtie.rb +9 -0
  52. data/lib/faml/ruby_multiline.rb +23 -0
  53. data/lib/faml/script_parser.rb +84 -0
  54. data/lib/faml/static_hash_parser.rb +113 -0
  55. data/lib/faml/syntax_error.rb +10 -0
  56. data/lib/faml/text_compiler.rb +69 -0
  57. data/lib/faml/tilt.rb +17 -0
  58. data/lib/faml/version.rb +3 -0
  59. data/spec/compiler_newline_spec.rb +162 -0
  60. data/spec/rails/Rakefile +6 -0
  61. data/spec/rails/app/assets/images/.keep +0 -0
  62. data/spec/rails/app/assets/javascripts/application.js +13 -0
  63. data/spec/rails/app/assets/stylesheets/application.css +15 -0
  64. data/spec/rails/app/controllers/application_controller.rb +5 -0
  65. data/spec/rails/app/controllers/books_controller.rb +8 -0
  66. data/spec/rails/app/controllers/concerns/.keep +0 -0
  67. data/spec/rails/app/helpers/application_helper.rb +2 -0
  68. data/spec/rails/app/mailers/.keep +0 -0
  69. data/spec/rails/app/models/.keep +0 -0
  70. data/spec/rails/app/models/book.rb +9 -0
  71. data/spec/rails/app/models/concerns/.keep +0 -0
  72. data/spec/rails/app/views/books/hello.html.haml +2 -0
  73. data/spec/rails/app/views/books/with_capture.html.haml +4 -0
  74. data/spec/rails/app/views/books/with_variables.html.haml +4 -0
  75. data/spec/rails/app/views/layouts/application.html.haml +9 -0
  76. data/spec/rails/bin/bundle +3 -0
  77. data/spec/rails/bin/rails +4 -0
  78. data/spec/rails/bin/rake +4 -0
  79. data/spec/rails/bin/setup +29 -0
  80. data/spec/rails/config.ru +4 -0
  81. data/spec/rails/config/application.rb +12 -0
  82. data/spec/rails/config/boot.rb +3 -0
  83. data/spec/rails/config/database.yml +25 -0
  84. data/spec/rails/config/environment.rb +5 -0
  85. data/spec/rails/config/environments/development.rb +41 -0
  86. data/spec/rails/config/environments/production.rb +79 -0
  87. data/spec/rails/config/environments/test.rb +42 -0
  88. data/spec/rails/config/initializers/assets.rb +11 -0
  89. data/spec/rails/config/initializers/backtrace_silencers.rb +7 -0
  90. data/spec/rails/config/initializers/cookies_serializer.rb +3 -0
  91. data/spec/rails/config/initializers/filter_parameter_logging.rb +4 -0
  92. data/spec/rails/config/initializers/inflections.rb +16 -0
  93. data/spec/rails/config/initializers/mime_types.rb +4 -0
  94. data/spec/rails/config/initializers/secret_key_base.rb +6 -0
  95. data/spec/rails/config/initializers/session_store.rb +3 -0
  96. data/spec/rails/config/initializers/wrap_parameters.rb +14 -0
  97. data/spec/rails/config/locales/en.yml +23 -0
  98. data/spec/rails/config/routes.rb +7 -0
  99. data/spec/rails/config/secrets.yml +22 -0
  100. data/spec/rails/db/seeds.rb +7 -0
  101. data/spec/rails/lib/assets/.keep +0 -0
  102. data/spec/rails/lib/tasks/.keep +0 -0
  103. data/spec/rails/log/.keep +0 -0
  104. data/spec/rails/public/404.html +67 -0
  105. data/spec/rails/public/422.html +67 -0
  106. data/spec/rails/public/500.html +66 -0
  107. data/spec/rails/public/favicon.ico +0 -0
  108. data/spec/rails/public/robots.txt +5 -0
  109. data/spec/rails/spec/requests/faml_spec.rb +41 -0
  110. data/spec/rails/vendor/assets/javascripts/.keep +0 -0
  111. data/spec/rails/vendor/assets/stylesheets/.keep +0 -0
  112. data/spec/rails_helper.rb +4 -0
  113. data/spec/render/attribute_spec.rb +241 -0
  114. data/spec/render/comment_spec.rb +61 -0
  115. data/spec/render/doctype_spec.rb +57 -0
  116. data/spec/render/element_spec.rb +136 -0
  117. data/spec/render/filters/cdata_spec.rb +12 -0
  118. data/spec/render/filters/coffee_spec.rb +25 -0
  119. data/spec/render/filters/css_spec.rb +45 -0
  120. data/spec/render/filters/escaped_spec.rb +14 -0
  121. data/spec/render/filters/javascript_spec.rb +44 -0
  122. data/spec/render/filters/markdown_spec.rb +19 -0
  123. data/spec/render/filters/plain_spec.rb +24 -0
  124. data/spec/render/filters/preserve_spec.rb +24 -0
  125. data/spec/render/filters/ruby_spec.rb +13 -0
  126. data/spec/render/filters/sass_spec.rb +28 -0
  127. data/spec/render/filters/scss_spec.rb +32 -0
  128. data/spec/render/filters_spec.rb +11 -0
  129. data/spec/render/haml_comment_spec.rb +24 -0
  130. data/spec/render/multiline_spec.rb +39 -0
  131. data/spec/render/newline_spec.rb +83 -0
  132. data/spec/render/plain_spec.rb +20 -0
  133. data/spec/render/preserve_spec.rb +8 -0
  134. data/spec/render/sanitize_spec.rb +36 -0
  135. data/spec/render/script_spec.rb +81 -0
  136. data/spec/render/silent_script_spec.rb +97 -0
  137. data/spec/render/unescape_spec.rb +45 -0
  138. data/spec/spec_helper.rb +47 -0
  139. data/spec/tilt_spec.rb +33 -0
  140. metadata +489 -0
@@ -0,0 +1,10 @@
1
+ module Faml
2
+ class SyntaxError < StandardError
3
+ attr_reader :lineno
4
+
5
+ def initialize(message, lineno)
6
+ super("#{message} at line #{lineno}")
7
+ @lineno = lineno
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,69 @@
1
+ require 'strscan'
2
+ require 'faml/parser_utils'
3
+
4
+ module Faml
5
+ class TextCompiler
6
+ class InvalidInterpolation < StandardError
7
+ end
8
+
9
+ def initialize(escape_html: true)
10
+ @escape_html = escape_html
11
+ end
12
+
13
+ def compile(text, escape_html: @escape_html)
14
+ if self.class.contains_interpolation?(text)
15
+ compile_interpolation(text, escape_html: escape_html)
16
+ else
17
+ [:static, text]
18
+ end
19
+ end
20
+
21
+ INTERPOLATION_BEGIN = /(\\*)(#[\{$@])/o
22
+
23
+ def self.contains_interpolation?(text)
24
+ INTERPOLATION_BEGIN === text
25
+ end
26
+
27
+ private
28
+
29
+ def compile_interpolation(text, escape_html: @escape_html)
30
+ s = StringScanner.new(text)
31
+ temple = [:multi]
32
+ pos = s.pos
33
+ while s.scan_until(INTERPOLATION_BEGIN)
34
+ escapes = s[1].size
35
+ pre = s.string.byteslice(pos ... (s.pos - s.matched.size))
36
+ temple << [:static, pre] << [:static, "\\" * (escapes/2)]
37
+ if escapes % 2 == 0
38
+ # perform interpolation
39
+ if s[2] == '#{'
40
+ temple << [:escape, escape_html, [:dynamic, find_close_brace(s)]]
41
+ else
42
+ var = s[2][-1]
43
+ s.scan(/\w+/)
44
+ var << s.matched
45
+ temple << [:escape, escape_html, [:dynamic, var]]
46
+ end
47
+ else
48
+ # escaped
49
+ temple << [:static, s[2]]
50
+ end
51
+ pos = s.pos
52
+ end
53
+ temple << [:static, s.rest]
54
+ temple
55
+ end
56
+
57
+ INTERPOLATION_BRACE = /[\{\}]/o
58
+
59
+ def find_close_brace(scanner)
60
+ pos = scanner.pos
61
+ depth = ParserUtils.balance(scanner, '{', '}')
62
+ if depth != 0
63
+ raise InvalidInterpolation.new(scanner.string)
64
+ else
65
+ scanner.string.byteslice(pos ... (scanner.pos-1))
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,17 @@
1
+ require 'tilt'
2
+ require 'faml/engine'
3
+
4
+ module Faml
5
+ class Tilt < Tilt::Template
6
+ def prepare
7
+ @code = Engine.new(options).call(data)
8
+ end
9
+
10
+ def precompiled_template(locals = {})
11
+ @code
12
+ end
13
+ end
14
+
15
+ ::Tilt.register(Tilt, 'haml')
16
+ ::Tilt.register(Tilt, 'faml')
17
+ end
@@ -0,0 +1,3 @@
1
+ module Faml
2
+ VERSION = "0.2.0"
3
+ end
@@ -0,0 +1,162 @@
1
+ require 'spec_helper'
2
+
3
+ class LineVerifier < StandardError
4
+ def initialize
5
+ super("raised at #{caller_locations(1, 1)[0].lineno}")
6
+ end
7
+ end
8
+
9
+ module LineVerifierHelper
10
+ extend RSpec::Matchers::DSL
11
+
12
+ matcher :raised_at do |expected|
13
+ match do |actual|
14
+ actual == "raised at #{expected}"
15
+ end
16
+ end
17
+ end
18
+
19
+ RSpec.describe 'Faml::Compiler newline generation', type: :render do
20
+ include LineVerifierHelper
21
+
22
+ it do
23
+ expect { render_string(<<HAML) }.to raise_error(LineVerifier, raised_at(3))
24
+ %div
25
+ %span= 1
26
+ %span>= raise LineVerifier
27
+ HAML
28
+ end
29
+
30
+ it do
31
+ expect { render_string(<<HAML) }.to raise_error(LineVerifier, raised_at(2))
32
+ %img
33
+ %img{href: raise(LineVerifier)}>
34
+ %img
35
+ HAML
36
+ end
37
+
38
+ it do
39
+ expect { render_string(<<'HAML') }.to raise_error(LineVerifier, raised_at(3))
40
+ %div
41
+ %span hello
42
+ %span #{raise LineVerifier}
43
+ %span world
44
+ HAML
45
+ end
46
+
47
+ it do
48
+ expect { render_string(<<HAML) }.to raise_error(LineVerifier, raised_at(2))
49
+
50
+ %div= raise LineVerifier
51
+ HAML
52
+ end
53
+
54
+ it 'keeps empty lines' do
55
+ expect { render_string(<<HAML) }.to raise_error(LineVerifier, raised_at(4))
56
+ %div
57
+ %span= 1
58
+
59
+ %span= raise LineVerifier
60
+ HAML
61
+ end
62
+
63
+ it 'keeps leading empty lines' do
64
+ expect { render_string(<<HAML) }.to raise_error(LineVerifier, raised_at(3))
65
+ %div
66
+
67
+ %span= raise LineVerifier
68
+ HAML
69
+ end
70
+
71
+ it 'counts haml comments' do
72
+ expect { render_string(<<HAML) }.to raise_error(LineVerifier, raised_at(3))
73
+ -# foo
74
+ bar
75
+ %span= raise LineVerifier
76
+ HAML
77
+ end
78
+
79
+ context 'with conditional comment' do
80
+ it do
81
+ expect { render_string(<<HAML) }.to raise_error(LineVerifier, raised_at(3))
82
+ %div
83
+ / [if IE]
84
+ %span= raise LineVerifier
85
+ HAML
86
+ end
87
+
88
+ it do
89
+ expect { render_string(<<HAML) }.to raise_error(LineVerifier, raised_at(4))
90
+ %div
91
+ / [if IE]
92
+ %span hello
93
+ %span= raise LineVerifier
94
+ HAML
95
+ end
96
+ end
97
+
98
+ context 'with filters' do
99
+ it do
100
+ expect { render_string(<<HAML) }.to raise_error(LineVerifier, raised_at(5))
101
+ :plain
102
+ hello
103
+
104
+
105
+ = raise LineVerifier
106
+ HAML
107
+ end
108
+
109
+ context 'with interpolation' do
110
+ it do
111
+ expect { render_string(<<'HAML') }.to raise_error(LineVerifier, raised_at(5))
112
+ :plain
113
+ #{'hello'}
114
+
115
+
116
+ = raise LineVerifier
117
+ HAML
118
+ end
119
+ end
120
+ end
121
+
122
+ context 'with tilt filters' do
123
+ it 'keeps newlines in filter' do
124
+ expect { render_string(<<'HAML') }.to raise_error(LineVerifier, raised_at(4))
125
+ :scss
126
+ nav {
127
+ ul {
128
+ margin: #{raise LineVerifier}px;
129
+ }
130
+ }
131
+ HAML
132
+ end
133
+
134
+ it 'keeps newlines after filter' do
135
+ expect { render_string(<<'HAML') }.to raise_error(LineVerifier, raised_at(8))
136
+ :scss
137
+ nav {
138
+ ul {
139
+ margin: 0;
140
+ }
141
+ }
142
+
143
+ %span= raise LineVerifier
144
+ HAML
145
+ end
146
+
147
+ context 'with interpolation' do
148
+ it 'keeps newlines after filter' do
149
+ expect { render_string(<<'HAML') }.to raise_error(LineVerifier, raised_at(8))
150
+ :scss
151
+ nav {
152
+ ul {
153
+ margin: #{0 + 5}px;
154
+ }
155
+ }
156
+
157
+ %span= raise LineVerifier
158
+ HAML
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require File.expand_path('../config/application', __FILE__)
5
+
6
+ Rails.application.load_tasks
File without changes
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any styles
10
+ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11
+ * file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,5 @@
1
+ class ApplicationController < ActionController::Base
2
+ # Prevent CSRF attacks by raising an exception.
3
+ # For APIs, you may want to use :null_session instead.
4
+ protect_from_forgery with: :exception
5
+ end
@@ -0,0 +1,8 @@
1
+ class BooksController < ApplicationController
2
+ def hello
3
+ end
4
+
5
+ def with_variables
6
+ @book = Book.new(params.permit(:title))
7
+ end
8
+ end
@@ -0,0 +1,2 @@
1
+ module ApplicationHelper
2
+ end
File without changes
File without changes
@@ -0,0 +1,9 @@
1
+ class Book
2
+ include ActiveModel::Model
3
+
4
+ attr_accessor :title
5
+
6
+ def to_s
7
+ "<span>#{title}</span>".html_safe
8
+ end
9
+ end
File without changes
@@ -0,0 +1,2 @@
1
+ .container
2
+ %span Hello, World
@@ -0,0 +1,4 @@
1
+ - html = capture do
2
+ %div
3
+ %p Hello
4
+ %div= html
@@ -0,0 +1,4 @@
1
+ %h1 Book
2
+ %p= @book.title
3
+ = link_to 'hello', books_hello_path
4
+ = @book
@@ -0,0 +1,9 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %title TestApp
5
+ = stylesheet_link_tag 'application', media: 'all'
6
+ = javascript_include_tag 'application'
7
+ = csrf_meta_tags
8
+
9
+ = yield
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3
+ load Gem.bin_path('bundler', 'bundle')
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
3
+ require_relative '../config/boot'
4
+ require 'rails/commands'
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../config/boot'
3
+ require 'rake'
4
+ Rake.application.run
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ require 'pathname'
3
+
4
+ # path to your application root.
5
+ APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
6
+
7
+ Dir.chdir APP_ROOT do
8
+ # This script is a starting point to setup your application.
9
+ # Add necessary setup steps to this file:
10
+
11
+ puts "== Installing dependencies =="
12
+ system "gem install bundler --conservative"
13
+ system "bundle check || bundle install"
14
+
15
+ # puts "\n== Copying sample files =="
16
+ # unless File.exist?("config/database.yml")
17
+ # system "cp config/database.yml.sample config/database.yml"
18
+ # end
19
+
20
+ puts "\n== Preparing database =="
21
+ system "bin/rake db:setup"
22
+
23
+ puts "\n== Removing old logs and tempfiles =="
24
+ system "rm -f log/*"
25
+ system "rm -rf tmp/cache"
26
+
27
+ puts "\n== Restarting application server =="
28
+ system "touch tmp/restart.txt"
29
+ end
@@ -0,0 +1,4 @@
1
+ # This file is used by Rack-based servers to start the application.
2
+
3
+ require ::File.expand_path('../config/environment', __FILE__)
4
+ run Rails.application
@@ -0,0 +1,12 @@
1
+ require File.expand_path('../boot', __FILE__)
2
+
3
+ require 'rails/all'
4
+
5
+ # Require the gems listed in Gemfile, including any gems
6
+ # you've limited to :test, :development, or :production.
7
+ Bundler.require(*Rails.groups)
8
+
9
+ module TestApp
10
+ class Application < Rails::Application
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
2
+
3
+ require 'bundler/setup' # Set up gems listed in the Gemfile.