rux 1.2.0 → 1.3.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/Gemfile +7 -0
- data/bin/ruxc +27 -2
- data/bin/ruxlex +13 -0
- data/lib/rux/default_visitor.rb +10 -7
- data/lib/rux/lex/states.csv +51 -50
- data/lib/rux/lexer.rb +13 -0
- data/lib/rux/parser.rb +10 -4
- data/lib/rux/ruby_lexer.rb +31 -8
- data/lib/rux/rux_lexer.rb +1 -1
- data/lib/rux/version.rb +1 -1
- data/lib/rux.rb +2 -3
- data/rux.gemspec +3 -1
- data/spec/parser/attributes_spec.rb +24 -0
- data/spec/parser/fragment_spec.rb +17 -0
- data/spec/parser_spec.rb +50 -1
- data/spec/render_spec.rb +1 -1
- metadata +21 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e2874b5336b991b08b274df04219d2c7b97247580f0587dfc3b6860e913d8af8
|
|
4
|
+
data.tar.gz: ba582dd96d6c58da357295e60267f4db9a6cdf47ddc99aa2740d590a1cec530d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c6c663d6d237fb6fc044dc2ebfa9c706d54eb5cdd3bc7a50011d82578ac7aab36a8f6c1ca466754f44bfed73ce708fc57bbd0ea3951681febd79f2730e7fd1d7
|
|
7
|
+
data.tar.gz: fb52a3a10cb3db47817acc7d760210758bc733b3b74b4ebfc9d241039d8d38ce00d4622957fd26effa7593acefe4d9387ebce9bcc6bab7dd20d83e9523b62322
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
# 1.3.0
|
|
2
|
+
* Automatically add generated files to an ignore file, eg. .gitignore.
|
|
3
|
+
- Pass the --ignore-path=PATH flag to ruxc to indicate the file to update.
|
|
4
|
+
* Add the ruxlex executable that prints parser tokens for debugging purposes.
|
|
5
|
+
* Preserve Ruby comments in generated files.
|
|
6
|
+
* Fix the `as:` argument, which was being improperly generated in earlier versions.
|
|
7
|
+
* General parser improvements.
|
|
8
|
+
- Allows fragments to be nested within other tags.
|
|
9
|
+
- Allows tags after ruby code in branch structures like `if..else`.
|
|
10
|
+
* Allows HTML attributes to start with `@`.
|
|
11
|
+
|
|
1
12
|
# 1.2.0
|
|
2
13
|
* Improve output safety.
|
|
3
14
|
- HTML tags are now automatically escaped when they come from Ruby code.
|
data/Gemfile
CHANGED
data/bin/ruxc
CHANGED
|
@@ -5,6 +5,7 @@ $:.push(File.expand_path('./lib'))
|
|
|
5
5
|
require 'pathname'
|
|
6
6
|
require 'optparse'
|
|
7
7
|
require 'rux'
|
|
8
|
+
require 'onload'
|
|
8
9
|
|
|
9
10
|
class RuxCLI
|
|
10
11
|
def self.parse(argv)
|
|
@@ -15,7 +16,8 @@ class RuxCLI
|
|
|
15
16
|
|
|
16
17
|
options = {
|
|
17
18
|
pretty: true,
|
|
18
|
-
stdout: false
|
|
19
|
+
stdout: false,
|
|
20
|
+
ignore_path: nil,
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
if argv.first != '-h' && argv.first != '--help'
|
|
@@ -41,6 +43,14 @@ class RuxCLI
|
|
|
41
43
|
end
|
|
42
44
|
end
|
|
43
45
|
|
|
46
|
+
oneline(<<~DESC).tap do |desc|
|
|
47
|
+
Update the given git ignore file with transpiled file paths.
|
|
48
|
+
DESC
|
|
49
|
+
opts.on('-i', '--ignore-path=PATH', desc) do |ignore_path|
|
|
50
|
+
options[:ignore_path] = ignore_path
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
44
54
|
opts.on('-h', '--help', 'Prints this help info') do
|
|
45
55
|
puts opts
|
|
46
56
|
exit
|
|
@@ -91,8 +101,17 @@ class RuxCLI
|
|
|
91
101
|
@options[:stdout]
|
|
92
102
|
end
|
|
93
103
|
|
|
104
|
+
def ignore_file
|
|
105
|
+
return nil unless ignore_path
|
|
106
|
+
@ignore_file ||= Onload::IgnoreFile.load(ignore_path)
|
|
107
|
+
end
|
|
108
|
+
|
|
94
109
|
private
|
|
95
110
|
|
|
111
|
+
def ignore_path
|
|
112
|
+
@options[:ignore_path]
|
|
113
|
+
end
|
|
114
|
+
|
|
96
115
|
def directory?
|
|
97
116
|
File.directory?(in_path)
|
|
98
117
|
end
|
|
@@ -101,7 +120,11 @@ end
|
|
|
101
120
|
cli = RuxCLI.parse(ARGV)
|
|
102
121
|
cli.validate
|
|
103
122
|
|
|
104
|
-
|
|
123
|
+
at_exit do
|
|
124
|
+
cli.ignore_file&.persist!
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
cli.each_file do |in_file, out_file|
|
|
105
128
|
rux_file = Rux::File.new(in_file)
|
|
106
129
|
|
|
107
130
|
if cli.write_to_stdout?
|
|
@@ -109,5 +132,7 @@ cli.each_file do |in_file, out_file, rbi_file|
|
|
|
109
132
|
else
|
|
110
133
|
rux_file.write(out_file, pretty: cli.pretty?)
|
|
111
134
|
puts "Wrote #{out_file}"
|
|
135
|
+
|
|
136
|
+
cli.ignore_file&.add(out_file)
|
|
112
137
|
end
|
|
113
138
|
end
|
data/bin/ruxlex
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#! /usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
$:.push(File.expand_path('./lib'))
|
|
4
|
+
|
|
5
|
+
require 'rux'
|
|
6
|
+
|
|
7
|
+
code = STDIN.read
|
|
8
|
+
result = Rux::Lexer.lex(code)
|
|
9
|
+
|
|
10
|
+
result.each do |(type, (str, loc))|
|
|
11
|
+
loc_str = loc.to_range.to_s.rjust(12, " ")
|
|
12
|
+
puts "#{loc_str} #{type} #{str.inspect}"
|
|
13
|
+
end
|
data/lib/rux/default_visitor.rb
CHANGED
|
@@ -32,7 +32,7 @@ module Rux
|
|
|
32
32
|
def visit_tag(node)
|
|
33
33
|
''.tap do |result|
|
|
34
34
|
block_arg = if (as = node.attrs.get('as'))
|
|
35
|
-
visit(as)
|
|
35
|
+
visit(as.value)
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
block_arg ||= "rux_block_arg#{@render_stack.size}"
|
|
@@ -71,10 +71,7 @@ module Rux
|
|
|
71
71
|
result << "|#{block_arg}| " if block_arg && node.component?
|
|
72
72
|
result << "Rux.create_buffer.tap { |_rux_buf_| "
|
|
73
73
|
|
|
74
|
-
node.
|
|
75
|
-
result << append_statement_for(child)
|
|
76
|
-
end
|
|
77
|
-
|
|
74
|
+
result << visit_tag_children(node).join
|
|
78
75
|
result << " }.to_s }"
|
|
79
76
|
end
|
|
80
77
|
|
|
@@ -88,11 +85,17 @@ module Rux
|
|
|
88
85
|
end
|
|
89
86
|
end
|
|
90
87
|
|
|
88
|
+
def visit_tag_children(node)
|
|
89
|
+
node.children.map do |child|
|
|
90
|
+
append_statement_for(child)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
91
94
|
def append_statement_for(node)
|
|
92
95
|
if node.is_a?(AST::TextNode)
|
|
93
|
-
"_rux_buf_.safe_append(#{visit(node).strip});"
|
|
96
|
+
"_rux_buf_.safe_append(#{visit(node).strip.chomp(';')});"
|
|
94
97
|
else
|
|
95
|
-
"_rux_buf_.append(#{visit(node).strip});"
|
|
98
|
+
"_rux_buf_.append(#{visit(node).strip.chomp(';')});"
|
|
96
99
|
end
|
|
97
100
|
end
|
|
98
101
|
|
data/lib/rux/lex/states.csv
CHANGED
|
@@ -1,50 +1,51 @@
|
|
|
1
|
-
,[<],[a-zA-Z0-9_-_---:-:],[>],[/],(space),[=],"[""]",['],"[^""]",[^'],[{],[}],(default)
|
|
2
|
-
start,tag_open_test
|
|
3
|
-
tag_open_test
|
|
4
|
-
tag_open_start
|
|
5
|
-
tag_open_body
|
|
6
|
-
tag_open
|
|
7
|
-
tag_open_end
|
|
8
|
-
tag_close_start
|
|
9
|
-
tag_close_body
|
|
10
|
-
tag_close
|
|
11
|
-
tag_close_spaces_body
|
|
12
|
-
tag_close_spaces
|
|
13
|
-
tag_close_end
|
|
14
|
-
tag_self_closing
|
|
15
|
-
tag_self_closing_start
|
|
16
|
-
tag_self_closing_end
|
|
17
|
-
fragment_open
|
|
18
|
-
fragment_close
|
|
19
|
-
|
|
20
|
-
attribute_spaces_body,,attribute_spaces[0],attribute_spaces[0],attribute_spaces[0],attribute_spaces_body,,,,,,attribute_spaces[0],,
|
|
21
|
-
attribute_spaces*,,attribute_name_body,
|
|
22
|
-
attribute_name_body
|
|
23
|
-
attribute_name
|
|
24
|
-
attribute_equals_spaces_body
|
|
25
|
-
attribute_equals_spaces
|
|
26
|
-
|
|
27
|
-
attribute_value_spaces_body
|
|
28
|
-
attribute_value_spaces
|
|
29
|
-
attribute_value_dq_start
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
attribute_value_ruby_code
|
|
38
|
-
attribute_value_ruby_code_end
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
attribute_ruby_code
|
|
44
|
-
attribute_ruby_code_end
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
literal
|
|
48
|
-
literal_ruby_code_start
|
|
49
|
-
literal_ruby_code
|
|
50
|
-
literal_ruby_code_end
|
|
1
|
+
,[<],[@-@.-.],[a-zA-Z0-9_-_---:-:],[>],[/],(space),[=],"[""]",['],"[^""]",[^'],[{],[}],(default)
|
|
2
|
+
start,tag_open_test,,,,,,,,,,,literal_ruby_code_start,,literal_body
|
|
3
|
+
tag_open_test,,,tag_open_start[0],fragment_open,tag_close_start,,,,,,,,,
|
|
4
|
+
tag_open_start*,,,tag_open_body,,,,,,,,,,,
|
|
5
|
+
tag_open_body,,,tag_open_body,tag_open[0],tag_self_closing[0],tag_open[0],,,,,,,,
|
|
6
|
+
tag_open*,,,,tag_open_end,,attribute_spaces_body,,,,,,,,
|
|
7
|
+
tag_open_end*,,,,,,,,,,,,,,
|
|
8
|
+
tag_close_start*,,,tag_close_body,fragment_close,,,,,,,,,,
|
|
9
|
+
tag_close_body,,,tag_close_body,tag_close[0],,tag_close[0],,,,,,,,
|
|
10
|
+
tag_close*,,,,tag_close_end,tag_self_closing[0],tag_close_spaces_body,,,,,,,,
|
|
11
|
+
tag_close_spaces_body,,,,tag_close_spaces[0],,tag_close_spaces_body,,,,,,,,
|
|
12
|
+
tag_close_spaces*,,,,tag_close_end,,,,,,,,,,
|
|
13
|
+
tag_close_end*,,,,,,,,,,,,,,
|
|
14
|
+
tag_self_closing*,,,,,tag_self_closing_start,,,,,,,,,
|
|
15
|
+
tag_self_closing_start,,,,tag_self_closing_end,,,,,,,,,,
|
|
16
|
+
tag_self_closing_end*,,,,,,,,,,,,,,
|
|
17
|
+
fragment_open*,,,,,,,,,,,,,,
|
|
18
|
+
fragment_close*,,,,,,,,,,,,,,
|
|
19
|
+
,,,,,,,,,,,,,,
|
|
20
|
+
attribute_spaces_body,,attribute_spaces[0],attribute_spaces[0],attribute_spaces[0],attribute_spaces[0],attribute_spaces_body,,,,,,attribute_spaces[0],,
|
|
21
|
+
attribute_spaces*,,attribute_name_sigil,attribute_name_body,tag_open_end,tag_self_closing_start,,,,,,,attribute_ruby_code_start,,
|
|
22
|
+
attribute_name_sigil,,,,,,,,,,,,,,attribute_name_body
|
|
23
|
+
attribute_name_body,,,attribute_name_body,attribute_name[0],attribute_name[0],attribute_name[0],attribute_name[0],,,,,,,
|
|
24
|
+
attribute_name*,,,,tag_open_end,tag_self_closing_start,attribute_equals_spaces_body,attribute_equals,,,,,,,
|
|
25
|
+
attribute_equals_spaces_body,,,,attribute_equals_spaces[0],,attribute_equals_spaces_body,attribute_equals_spaces[0],,,,,,,attribute_equals_spaces[0]
|
|
26
|
+
attribute_equals_spaces*,,,,tag_open_end,tag_self_closing_start,,attribute_equals,,,,,,,attribute_name_sigil
|
|
27
|
+
attribute_equals*,,,attribute_value_uq_body,,,attribute_value_spaces_body[0],,attribute_value_dq_start,attribute_value_sq_start,,,attribute_value_ruby_code_start,,
|
|
28
|
+
attribute_value_spaces_body,,,attribute_value_spaces[0],attribute_value_spaces[0],attribute_value_spaces[0],attribute_value_spaces_body,,attribute_value_spaces[0],attribute_value_spaces[0],,,attribute_value_spaces[0],,
|
|
29
|
+
attribute_value_spaces*,,,attribute_value_uq_body,tag_open_end,tag_self_closing_start,,,attribute_value_dq_start,attribute_value_sq_start,,,attribute_value_ruby_code_start,,
|
|
30
|
+
attribute_value_dq_start*,,,,,,,,,,attribute_value_dq_body,,,,
|
|
31
|
+
attribute_value_sq_start*,,,,,,,,,,,attribute_value_sq_body,,,
|
|
32
|
+
attribute_value_dq_body,,,,,,,,attribute_dq_value[0],,attribute_value_dq_body,,,,
|
|
33
|
+
attribute_value_sq_body,,,,,,,,,attribute_sq_value[0],,attribute_value_sq_body,,,
|
|
34
|
+
attribute_value_uq_body,,,attribute_value_uq_body,attribute_uq_value[0],attrIbute_uq_value[0],attribute_uq_value[0],,,,,,,,
|
|
35
|
+
attribute_value_dq_end*,,,attribute_name,tag_open_end,tag_self_closing_start,attribute_spaces_body,,,,,,,,
|
|
36
|
+
attribute_value_sq_end*,,,attribute_name,tag_open_end,tag_self_closing_start,attribute_spaces_body,,,,,,,,
|
|
37
|
+
attribute_value_ruby_code_start*,,,,,,,,,,,,,,attribute_value_ruby_code
|
|
38
|
+
attribute_value_ruby_code*,,,,,,,,,,,,,attribute_value_ruby_code_end,
|
|
39
|
+
attribute_value_ruby_code_end*,,,attribute_name,tag_open_end,tag_self_closing_start,attribute_spaces_body,,,,,,,,
|
|
40
|
+
attribute_dq_value*,,,,,,,,attribute_value_dq_end,,,,,,
|
|
41
|
+
attribute_sq_value*,,,,,,,,,attribute_value_sq_end,,,,,
|
|
42
|
+
attribute_uq_value*,,,attribute_name,tag_open_end,tag_self_closing_start,attribute_spaces_body,,,,,,,,
|
|
43
|
+
attribute_ruby_code_start*,,,,,,,,,,,,,,attribute_ruby_code[0]
|
|
44
|
+
attribute_ruby_code*,,,,,,,,,,,,,attribute_ruby_code_end,
|
|
45
|
+
attribute_ruby_code_end*,,,attribute_name,tag_open_end,tag_self_closing_start,attribute_spaces_body,,,,,,,,
|
|
46
|
+
,,,,,,,,,,,,,,
|
|
47
|
+
literal_body,literal[0],,,,,,,,,,,literal[0],,literal_body
|
|
48
|
+
literal*,,,,,,,,,,,,literal_ruby_code_start,,
|
|
49
|
+
literal_ruby_code_start*,,,,,,,,,,,,,,literal_ruby_code[0]
|
|
50
|
+
literal_ruby_code*,,,,,,,,,,,,,literal_ruby_code_end,
|
|
51
|
+
literal_ruby_code_end*,,,,,,,,,,,,,,
|
data/lib/rux/lexer.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'parser'
|
|
2
|
+
|
|
1
3
|
module Rux
|
|
2
4
|
class Lexer
|
|
3
5
|
class EOFError < StandardError; end
|
|
@@ -5,6 +7,13 @@ module Rux
|
|
|
5
7
|
|
|
6
8
|
attr_reader :source_buffer
|
|
7
9
|
|
|
10
|
+
class << self
|
|
11
|
+
def lex(str)
|
|
12
|
+
buffer = ::Parser::Source::Buffer.new('(source)', source: str)
|
|
13
|
+
new(buffer).to_a
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
8
17
|
def initialize(source_buffer)
|
|
9
18
|
@source_buffer = source_buffer
|
|
10
19
|
@stack = [RubyLexer.new(source_buffer, 0)]
|
|
@@ -17,6 +26,10 @@ module Rux
|
|
|
17
26
|
[nil, ['$eof']]
|
|
18
27
|
end
|
|
19
28
|
|
|
29
|
+
def to_a
|
|
30
|
+
@generator.to_a
|
|
31
|
+
end
|
|
32
|
+
|
|
20
33
|
private
|
|
21
34
|
|
|
22
35
|
def each_token
|
data/lib/rux/parser.rb
CHANGED
|
@@ -8,14 +8,18 @@ module Rux
|
|
|
8
8
|
class << self
|
|
9
9
|
def parse_file(path)
|
|
10
10
|
buffer = ::Parser::Source::Buffer.new(path).read
|
|
11
|
-
|
|
12
|
-
new(lexer).parse
|
|
11
|
+
new(make_lexer(buffer)).parse
|
|
13
12
|
end
|
|
14
13
|
|
|
15
14
|
def parse(str)
|
|
16
15
|
buffer = ::Parser::Source::Buffer.new('(source)', source: str)
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
new(make_lexer(buffer)).parse
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def make_lexer(buffer)
|
|
22
|
+
::Rux::Lexer.new(buffer)
|
|
19
23
|
end
|
|
20
24
|
end
|
|
21
25
|
|
|
@@ -137,6 +141,8 @@ module Rux
|
|
|
137
141
|
if is?(:tRUX_LITERAL, :tRUX_LITERAL_RUBY_CODE_START)
|
|
138
142
|
lit = literal
|
|
139
143
|
node.children << lit if lit
|
|
144
|
+
elsif is?(:tRUX_FRAGMENT_OPEN)
|
|
145
|
+
node.children << fragment
|
|
140
146
|
else
|
|
141
147
|
node.children << tag
|
|
142
148
|
end
|
data/lib/rux/ruby_lexer.rb
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
module Rux
|
|
2
|
+
class TokenArrayProxy < Array
|
|
3
|
+
def initialize(rux_token_queue)
|
|
4
|
+
@rux_token_queue = rux_token_queue
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def push(token)
|
|
8
|
+
if token[0] == :tCOMMENT
|
|
9
|
+
@rux_token_queue.push(token)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
super
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
2
16
|
class RubyLexer < ::Parser::Lexer
|
|
3
17
|
# These are populated when ::Parser::Lexer loads and are therefore
|
|
4
18
|
# not inherited. We have to copy them over manually.
|
|
@@ -15,6 +29,8 @@ module Rux
|
|
|
15
29
|
@generator = to_enum(:each_token)
|
|
16
30
|
@rux_token_queue = []
|
|
17
31
|
@p = init_pos
|
|
32
|
+
|
|
33
|
+
self.tokens = TokenArrayProxy.new(@rux_token_queue)
|
|
18
34
|
end
|
|
19
35
|
|
|
20
36
|
alias_method :advance_orig, :advance
|
|
@@ -27,6 +43,7 @@ module Rux
|
|
|
27
43
|
@ts = @te = @p = pos
|
|
28
44
|
@eof = false
|
|
29
45
|
@rux_token_queue.clear
|
|
46
|
+
clear_queue
|
|
30
47
|
populate_queue
|
|
31
48
|
end
|
|
32
49
|
|
|
@@ -44,13 +61,7 @@ module Rux
|
|
|
44
61
|
end
|
|
45
62
|
|
|
46
63
|
def each_token(&block)
|
|
47
|
-
|
|
48
|
-
# ahead by 1 token; that's why the first element in @rux_token_queue is
|
|
49
|
-
# yielded immediately. If the lexer _starts_ at a rux tag however,
|
|
50
|
-
# lookahead is a lot more difficult. To mitigate, we insert a dummy skip
|
|
51
|
-
# token here. That way, at_rux? checks the right tokens in the queue and
|
|
52
|
-
# correctly identifies the start of a rux tag.
|
|
53
|
-
@rux_token_queue << [:tSKIP, ['$skip', make_range(@p, @p)]]
|
|
64
|
+
clear_queue
|
|
54
65
|
|
|
55
66
|
@eof = false
|
|
56
67
|
curlies = 1
|
|
@@ -74,7 +85,7 @@ module Rux
|
|
|
74
85
|
type, (_, pos) = token
|
|
75
86
|
|
|
76
87
|
case type
|
|
77
|
-
when :tLCURLY, :tLBRACE
|
|
88
|
+
when :tLCURLY, :tLBRACE, :tLAMBEG
|
|
78
89
|
curlies += 1
|
|
79
90
|
when :tRCURLY, :tRBRACE
|
|
80
91
|
curlies -= 1
|
|
@@ -111,6 +122,18 @@ module Rux
|
|
|
111
122
|
end
|
|
112
123
|
end
|
|
113
124
|
|
|
125
|
+
def clear_queue
|
|
126
|
+
@rux_token_queue.clear
|
|
127
|
+
|
|
128
|
+
# We detect whether or not we're at the beginning of a rux tag by looking
|
|
129
|
+
# ahead by 1 token; that's why the first element in @rux_token_queue is
|
|
130
|
+
# yielded immediately. If the lexer _starts_ at a rux tag however,
|
|
131
|
+
# lookahead is a lot more difficult. To mitigate, we insert a dummy skip
|
|
132
|
+
# token here. That way, at_rux? checks the right tokens in the queue and
|
|
133
|
+
# correctly identifies the start of a rux tag.
|
|
134
|
+
@rux_token_queue << [:tSKIP, ['$skip', make_range(@p, @p)]]
|
|
135
|
+
end
|
|
136
|
+
|
|
114
137
|
def at_rux?
|
|
115
138
|
at_lt? && !at_inheritance?
|
|
116
139
|
end
|
data/lib/rux/rux_lexer.rb
CHANGED
|
@@ -123,7 +123,7 @@ module Rux
|
|
|
123
123
|
|
|
124
124
|
unless cur_trans
|
|
125
125
|
raise Rux::Lexer::TransitionError,
|
|
126
|
-
"no transition found from #{cur_state} at position #{@p} while "\
|
|
126
|
+
"no transition found from #{cur_state} for #{chr.inspect} at position #{@p} while "\
|
|
127
127
|
'lexing rux code'
|
|
128
128
|
end
|
|
129
129
|
|
data/lib/rux/version.rb
CHANGED
data/lib/rux.rb
CHANGED
|
@@ -38,9 +38,8 @@ module Rux
|
|
|
38
38
|
ruby_code = visitor.visit(Parser.parse(str))
|
|
39
39
|
return ruby_code unless pretty
|
|
40
40
|
|
|
41
|
-
::
|
|
42
|
-
|
|
43
|
-
)
|
|
41
|
+
ast, comments = *::Parser::CurrentRuby.parse_with_comments(ruby_code)
|
|
42
|
+
::Unparser.unparse(ast, comments: comments)
|
|
44
43
|
end
|
|
45
44
|
|
|
46
45
|
def default_visitor
|
data/rux.gemspec
CHANGED
|
@@ -10,11 +10,13 @@ Gem::Specification.new do |s|
|
|
|
10
10
|
s.description = s.summary = 'A jsx-inspired way to write view components.'
|
|
11
11
|
s.platform = Gem::Platform::RUBY
|
|
12
12
|
|
|
13
|
+
s.add_dependency 'onload', '~> 1.1'
|
|
13
14
|
s.add_dependency 'parser', '~> 3.0'
|
|
14
|
-
s.add_dependency 'unparser', '~> 0.
|
|
15
|
+
s.add_dependency 'unparser', '~> 0.8'
|
|
15
16
|
|
|
16
17
|
s.require_path = 'lib'
|
|
17
18
|
s.executables << 'ruxc'
|
|
19
|
+
s.executables << 'ruxlex'
|
|
18
20
|
|
|
19
21
|
s.files = Dir['{lib,spec}/**/*', 'Gemfile', 'LICENSE', 'CHANGELOG.md', 'README.md', 'Rakefile', 'rux.gemspec']
|
|
20
22
|
end
|
|
@@ -94,4 +94,28 @@ describe 'attributes', type: :parser do
|
|
|
94
94
|
Rux.tag("div", { :"data-foo" => "bar" })
|
|
95
95
|
RUBY
|
|
96
96
|
end
|
|
97
|
+
|
|
98
|
+
it 'yields the component instance to the block using the as: argument for the variable name' do
|
|
99
|
+
code = <<~RUX
|
|
100
|
+
<Hello as={hello}>
|
|
101
|
+
{hello.foo}
|
|
102
|
+
</Hello>
|
|
103
|
+
RUX
|
|
104
|
+
expect(compile(code)).to eq(<<~RUBY.strip)
|
|
105
|
+
render(Hello.new) { |hello|
|
|
106
|
+
Rux.create_buffer.tap { |_rux_buf_|
|
|
107
|
+
_rux_buf_.append(hello.foo)
|
|
108
|
+
}.to_s
|
|
109
|
+
}
|
|
110
|
+
RUBY
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it 'allows attributes to start with @' do
|
|
114
|
+
code = <<~RUX
|
|
115
|
+
<div @click="alert('foo')" />
|
|
116
|
+
RUX
|
|
117
|
+
expect(compile(code)).to eq(<<~RUBY.strip)
|
|
118
|
+
Rux.tag("div", { :@click => "alert('foo')" })
|
|
119
|
+
RUBY
|
|
120
|
+
end
|
|
97
121
|
end
|
|
@@ -44,4 +44,21 @@ describe 'fragments', type: :parser do
|
|
|
44
44
|
}
|
|
45
45
|
RUBY
|
|
46
46
|
end
|
|
47
|
+
|
|
48
|
+
it 'allows fragments nested inside other tags' do
|
|
49
|
+
code = <<~RUX
|
|
50
|
+
<div>
|
|
51
|
+
<>{"foo"}</>
|
|
52
|
+
</div>
|
|
53
|
+
RUX
|
|
54
|
+
expect(compile(code)).to eq(<<~RUBY.strip)
|
|
55
|
+
Rux.tag("div") {
|
|
56
|
+
Rux.create_buffer.tap { |_rux_buf_|
|
|
57
|
+
_rux_buf_.append(Rux.create_buffer.tap { |_rux_buf_|
|
|
58
|
+
_rux_buf_.append("foo")
|
|
59
|
+
}.to_s)
|
|
60
|
+
}.to_s
|
|
61
|
+
}
|
|
62
|
+
RUBY
|
|
63
|
+
end
|
|
47
64
|
end
|
data/spec/parser_spec.rb
CHANGED
|
@@ -10,7 +10,7 @@ describe 'parsing', type: :parser do
|
|
|
10
10
|
it 'raises an error when no state transition can be found' do
|
|
11
11
|
expect { compile('<Hello <foo>') }.to(
|
|
12
12
|
raise_error(Rux::Lexer::TransitionError,
|
|
13
|
-
'no transition found from tRUX_ATTRIBUTE_SPACES_BODY at position 7 '\
|
|
13
|
+
'no transition found from tRUX_ATTRIBUTE_SPACES_BODY for "<" at position 7 '\
|
|
14
14
|
'while lexing rux code')
|
|
15
15
|
)
|
|
16
16
|
end
|
|
@@ -63,4 +63,53 @@ describe 'parsing', type: :parser do
|
|
|
63
63
|
}
|
|
64
64
|
RUBY
|
|
65
65
|
end
|
|
66
|
+
|
|
67
|
+
it 'preserves comments' do
|
|
68
|
+
code = <<~RUX
|
|
69
|
+
# frozen_string_literal: true
|
|
70
|
+
|
|
71
|
+
class Foo
|
|
72
|
+
def call
|
|
73
|
+
<p>Hello</p>
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
RUX
|
|
77
|
+
expect(compile(code)).to eq(<<~RUBY)
|
|
78
|
+
# frozen_string_literal: true
|
|
79
|
+
class Foo
|
|
80
|
+
def call
|
|
81
|
+
Rux.tag("p") {
|
|
82
|
+
Rux.create_buffer.tap { |_rux_buf_|
|
|
83
|
+
_rux_buf_.safe_append("Hello")
|
|
84
|
+
}.to_s
|
|
85
|
+
}
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
RUBY
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it 'allows a tag after ruby code in a branch situation' do
|
|
92
|
+
code = <<~RUX
|
|
93
|
+
<div>
|
|
94
|
+
{if foo
|
|
95
|
+
<>foo</>
|
|
96
|
+
else
|
|
97
|
+
<div></div>
|
|
98
|
+
end}
|
|
99
|
+
</div>
|
|
100
|
+
RUX
|
|
101
|
+
expect(compile(code)).to eq(<<~RUBY.strip)
|
|
102
|
+
Rux.tag("div") {
|
|
103
|
+
Rux.create_buffer.tap { |_rux_buf_|
|
|
104
|
+
_rux_buf_.append(if foo
|
|
105
|
+
Rux.create_buffer.tap { |_rux_buf_|
|
|
106
|
+
_rux_buf_.safe_append("foo")
|
|
107
|
+
}.to_s
|
|
108
|
+
else
|
|
109
|
+
Rux.tag("div")
|
|
110
|
+
end)
|
|
111
|
+
}.to_s
|
|
112
|
+
}
|
|
113
|
+
RUBY
|
|
114
|
+
end
|
|
66
115
|
end
|
data/spec/render_spec.rb
CHANGED
metadata
CHANGED
|
@@ -1,15 +1,28 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rux
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Cameron Dutro
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: onload
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '1.1'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '1.1'
|
|
13
26
|
- !ruby/object:Gem::Dependency
|
|
14
27
|
name: parser
|
|
15
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -30,19 +43,20 @@ dependencies:
|
|
|
30
43
|
requirements:
|
|
31
44
|
- - "~>"
|
|
32
45
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '0.
|
|
46
|
+
version: '0.8'
|
|
34
47
|
type: :runtime
|
|
35
48
|
prerelease: false
|
|
36
49
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
50
|
requirements:
|
|
38
51
|
- - "~>"
|
|
39
52
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '0.
|
|
53
|
+
version: '0.8'
|
|
41
54
|
description: A jsx-inspired way to write view components.
|
|
42
55
|
email:
|
|
43
56
|
- camertron@gmail.com
|
|
44
57
|
executables:
|
|
45
58
|
- ruxc
|
|
59
|
+
- ruxlex
|
|
46
60
|
extensions: []
|
|
47
61
|
extra_rdoc_files: []
|
|
48
62
|
files:
|
|
@@ -52,6 +66,7 @@ files:
|
|
|
52
66
|
- README.md
|
|
53
67
|
- Rakefile
|
|
54
68
|
- bin/ruxc
|
|
69
|
+
- bin/ruxlex
|
|
55
70
|
- lib/rux.rb
|
|
56
71
|
- lib/rux/ast.rb
|
|
57
72
|
- lib/rux/ast/attr_node.rb
|
|
@@ -97,7 +112,6 @@ files:
|
|
|
97
112
|
homepage: http://github.com/camertron/rux
|
|
98
113
|
licenses: []
|
|
99
114
|
metadata: {}
|
|
100
|
-
post_install_message:
|
|
101
115
|
rdoc_options: []
|
|
102
116
|
require_paths:
|
|
103
117
|
- lib
|
|
@@ -112,8 +126,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
112
126
|
- !ruby/object:Gem::Version
|
|
113
127
|
version: '0'
|
|
114
128
|
requirements: []
|
|
115
|
-
rubygems_version: 3.
|
|
116
|
-
signing_key:
|
|
129
|
+
rubygems_version: 3.6.7
|
|
117
130
|
specification_version: 4
|
|
118
131
|
summary: A jsx-inspired way to write view components.
|
|
119
132
|
test_files: []
|