gloss 0.0.4 → 0.0.5
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/.rspec +1 -0
- data/Gemfile.lock +8 -10
- data/ext/gloss/spec/parser_spec.cr +83 -83
- data/ext/gloss/src/cr_ast.cr +3 -1
- data/ext/gloss/src/rb_ast.cr +4 -3
- data/lib/gloss/builder.rb +52 -40
- data/lib/gloss/cli.rb +33 -28
- data/lib/gloss/config.rb +7 -2
- data/lib/gloss/initializer.rb +5 -5
- data/lib/gloss/version.rb +2 -2
- data/lib/gloss/watcher.rb +17 -3
- data/lib/gloss/writer.rb +2 -2
- data/src/lib/gloss/builder.gl +64 -40
- data/src/lib/gloss/cli.gl +26 -23
- data/src/lib/gloss/config.gl +7 -1
- data/src/lib/gloss/initializer.gl +4 -6
- data/src/lib/gloss/version.gl +1 -1
- data/src/lib/gloss/watcher.gl +19 -3
- data/src/lib/gloss/writer.gl +2 -2
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a26f64e872c2884f2fa5969d762e66ed6f1346732933f08ae7b92eb07aea5ab3
|
|
4
|
+
data.tar.gz: 9cf39520e8dc43e6a74f9ea606a719815e2bd503d19744c7979478f746b8345f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bdb98f72e57945e9de8bbd03296d95b2cfc221f915e7e8e8fd511e8b4794ef3bb65f1830d9769486c30a004595c3a7f84e3e785bb1b1297d778cff984a0a3234
|
|
7
|
+
data.tar.gz: 9758d730e858adf27c60f89ec9e88ffb07d3950d2a4f493b1d0ad2b00b7a10999fd76c9ae802753428fdfb0cab005adfe773456c415b504809217507ac30fbc5
|
data/.rspec
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
--require spec_helper
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
gloss (0.0.
|
|
4
|
+
gloss (0.0.5)
|
|
5
5
|
fast_blank
|
|
6
6
|
listen
|
|
7
7
|
rbs
|
|
@@ -17,9 +17,8 @@ GEM
|
|
|
17
17
|
tzinfo (~> 2.0)
|
|
18
18
|
zeitwerk (~> 2.3)
|
|
19
19
|
ast (2.4.1)
|
|
20
|
-
ast_utils (0.
|
|
21
|
-
parser (
|
|
22
|
-
thor (>= 0.19)
|
|
20
|
+
ast_utils (0.4.0)
|
|
21
|
+
parser (>= 2.7.0)
|
|
23
22
|
byebug (11.1.3)
|
|
24
23
|
coderay (1.1.3)
|
|
25
24
|
concurrent-ruby (1.1.8)
|
|
@@ -50,7 +49,7 @@ GEM
|
|
|
50
49
|
rb-fsevent (0.10.4)
|
|
51
50
|
rb-inotify (0.10.1)
|
|
52
51
|
ffi (~> 1.0)
|
|
53
|
-
rbs (1.0.
|
|
52
|
+
rbs (1.0.4)
|
|
54
53
|
regexp_parser (2.0.3)
|
|
55
54
|
rexml (3.2.4)
|
|
56
55
|
rspec (3.10.0)
|
|
@@ -78,15 +77,14 @@ GEM
|
|
|
78
77
|
rubocop-ast (1.4.0)
|
|
79
78
|
parser (>= 2.7.1.5)
|
|
80
79
|
ruby-progressbar (1.11.0)
|
|
81
|
-
steep (0.
|
|
80
|
+
steep (0.40.0)
|
|
82
81
|
activesupport (>= 5.1)
|
|
83
|
-
ast_utils (
|
|
82
|
+
ast_utils (>= 0.4.0)
|
|
84
83
|
language_server-protocol (~> 3.15.0.1)
|
|
85
84
|
listen (~> 3.0)
|
|
86
|
-
parser (
|
|
85
|
+
parser (>= 2.7)
|
|
87
86
|
rainbow (>= 2.2.2, < 4.0)
|
|
88
|
-
rbs (~> 1.0.
|
|
89
|
-
thor (1.1.0)
|
|
87
|
+
rbs (~> 1.0.3)
|
|
90
88
|
tzinfo (2.0.4)
|
|
91
89
|
concurrent-ruby (~> 1.0)
|
|
92
90
|
unicode-display_width (1.7.0)
|
|
@@ -16,13 +16,13 @@ module Gloss
|
|
|
16
16
|
Gloss.parse_string("hsh = {}").should be_truthy
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
it "parses all kinds of method args" do
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
end
|
|
19
|
+
# it "parses all kinds of method args" do
|
|
20
|
+
# output = %q|{"type":"DefNode","name":"abc","body":null,"rp_args":[{"type":"Arg","name":"a","external_name":"a","default_value":null,"restriction":{"type":"Path","value":"Float"},"keyword_arg":false},{"type":"Arg","name":"b","external_name":"b","default_value":null,"restriction":null,"keyword_arg":false},{"type":"Arg","name":"c","external_name":"c","default_value":null,"restriction":null,"keyword_arg":false,splat: "true"},{"type":"Arg","name":"d","external_name":"d","default_value":{"type":"LiteralNode","value":"nil","rb_type":"NilClass"},"restriction":{"type":"Union","types":[{"type":"Path","value":"String"},{"type":"Path","value":"Nil"}]},"keyword_arg":false},{"type":"Arg","name":"e","external_name":"e","default_value":null,"restriction":{"type":"Path","value":"Integer"},"keyword_arg":true},{"type":"Arg","name":"f","external_name":"f","default_value":null,"restriction":null,"keyword_arg":true},{"type":"Arg","name":"g","external_name":"g","default_value":{"type":"LiteralNode","value":"nil","rb_type":"NilClass"},"restriction":{"type":"Path","value":"String"},"keyword_arg":true}],"receiver":null,"return_type":null,"rest_kw_args":{"type":"Arg","name":"h","external_name":"h","default_value":null,"restriction":null,"keyword_arg":false}}|
|
|
21
|
+
# Gloss.parse_string(<<-GLS).should eq output
|
|
22
|
+
# def abc(a : Float, b, *c, d : String? = nil, e: : Integer, f:, g: : String = nil, **h)
|
|
23
|
+
# end
|
|
24
|
+
# GLS
|
|
25
|
+
# end
|
|
26
26
|
|
|
27
27
|
it "parses rescue with ruby syntax" do
|
|
28
28
|
Gloss.parse_string(<<-GLOSS).should be_truthy
|
|
@@ -35,90 +35,90 @@ module Gloss
|
|
|
35
35
|
end
|
|
36
36
|
GLOSS
|
|
37
37
|
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
it "parses shorthand blocks with ruby syntax" do
|
|
41
|
-
Gloss.parse_string("[1].map(&:to_s)").should eq(
|
|
42
|
-
%q<{"type":"Call","name":"map","args":[],"object":{"type":"ArrayLiteral","elements":[{"type":"LiteralNode","value":"1","rb_type":"Integer"}],"frozen":false},"block":null,"block_arg":{"type":"LiteralNode","value":":to_s","rb_type":"Symbol"}}>
|
|
43
|
-
)
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
it "parses tuples as frozen arrays" do
|
|
47
|
-
Gloss.parse_string("{ 'hello', 'world' }").should eq(
|
|
48
|
-
%q<{"type":"ArrayLiteral","elements":[{"type":"LiteralNode","value":"\"hello\"","rb_type":"String"},{"type":"LiteralNode","value":"\"world\"","rb_type":"String"}],"frozen":true}>
|
|
49
|
-
)
|
|
50
|
-
end
|
|
51
38
|
|
|
52
|
-
|
|
53
|
-
Gloss.parse_string("
|
|
54
|
-
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
it "parses the and operator" do
|
|
59
|
-
Gloss.parse_string("puts 'hello world' if 1 and 2").should be_truthy
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
it "parses the or operator" do
|
|
63
|
-
Gloss.parse_string("puts 'hello world' if true or false").should be_truthy
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
it "parses the not operator" do
|
|
67
|
-
Gloss.parse_string("puts 'hello world' if true and not false").should be_truthy
|
|
68
|
-
end
|
|
39
|
+
# it "parses shorthand blocks with ruby syntax" do
|
|
40
|
+
# Gloss.parse_string("[1].map(&:to_s)").should eq(
|
|
41
|
+
# %q<{"type":"Call","name":"map","args":[],"object":{"type":"ArrayLiteral","elements":[{"type":"LiteralNode","value":"1","rb_type":"Integer"}],"frozen":false},"block":null,"block_arg":{"type":"LiteralNode","value":":to_s","rb_type":"Symbol"}}>
|
|
42
|
+
# )
|
|
43
|
+
# end
|
|
69
44
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
it "parses for loops" do
|
|
77
|
-
Gloss.parse_string(<<-GLS).should be_truthy
|
|
78
|
-
for k, v in { hello: world }
|
|
79
|
-
puts key: k, value: v
|
|
80
|
-
end
|
|
81
|
-
GLS
|
|
82
|
-
end
|
|
45
|
+
it "parses tuples as frozen arrays" do
|
|
46
|
+
Gloss.parse_string("{ 'hello', 'world' }").should eq(
|
|
47
|
+
%q<{"type":"ArrayLiteral","elements":[{"type":"LiteralNode","value":"\"hello\"","rb_type":"String"},{"type":"LiteralNode","value":"\"world\"","rb_type":"String"}],"frozen":true}>
|
|
48
|
+
)
|
|
49
|
+
end
|
|
83
50
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
GLS
|
|
90
|
-
end
|
|
51
|
+
it "parses named tuples as frozen hashes" do
|
|
52
|
+
Gloss.parse_string("{ hello: 'world' }").should eq(
|
|
53
|
+
%q<{"type":"HashLiteral","elements":[["hello",{"type":"LiteralNode","value":"\"world\"","rb_type":"String"}]],"frozen":true}>
|
|
54
|
+
)
|
|
55
|
+
end
|
|
91
56
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
Gloss.parse_string(<<-GLS).should eq expected
|
|
96
|
-
case "abc"
|
|
97
|
-
when .start_with? 'a'
|
|
98
|
-
1
|
|
99
|
-
else
|
|
100
|
-
0
|
|
101
|
-
end
|
|
102
|
-
GLS
|
|
103
|
-
end
|
|
57
|
+
# it "parses the and operator" do
|
|
58
|
+
# Gloss.parse_string("puts 'hello world' if 1 and 2").should be_truthy
|
|
59
|
+
# end
|
|
104
60
|
|
|
105
|
-
|
|
106
|
-
Gloss.parse_string(
|
|
107
|
-
|
|
108
|
-
end
|
|
61
|
+
# it "parses the or operator" do
|
|
62
|
+
# Gloss.parse_string("puts 'hello world' if true or false").should be_truthy
|
|
63
|
+
# end
|
|
109
64
|
|
|
110
|
-
|
|
65
|
+
# it "parses the not operator" do
|
|
66
|
+
# Gloss.parse_string("puts 'hello world' if true and not false").should be_truthy
|
|
67
|
+
# end
|
|
111
68
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
69
|
+
it "parses global variables" do
|
|
70
|
+
Gloss.parse_string("$var : String = 'hello world'").should eq(
|
|
71
|
+
%q|{"type":"TypeDeclaration","var":{"type":"GlobalVar","name":"$var"},"declared_type":{"type":"Path","value":"String"},"value":{"type":"LiteralNode","value":"\"hello world\"","rb_type":"String"},"var_type":"GlobalVar"}|
|
|
72
|
+
)
|
|
73
|
+
end
|
|
115
74
|
|
|
116
|
-
|
|
117
|
-
Gloss.parse_string(<<-GLS).should
|
|
118
|
-
|
|
119
|
-
|
|
75
|
+
# it "parses for loops" do
|
|
76
|
+
# Gloss.parse_string(<<-GLS).should be_truthy
|
|
77
|
+
# for k, v in { hello: world }
|
|
78
|
+
# puts key: k, value: v
|
|
79
|
+
# end
|
|
80
|
+
# GLS
|
|
81
|
+
# end
|
|
82
|
+
|
|
83
|
+
it "parses generics as RBS generics" do
|
|
84
|
+
expected =
|
|
85
|
+
%q|{"type":"TypeDeclaration","var":{"type":"Var","name":"hsh"},"declared_type":{"type":"Generic","name":{"type":"Path","value":"Hash"},"args":[{"type":"Path","value":"String"},{"type":"Path","value":"String"}]},"value":{"type":"HashLiteral","elements":[[{"type":"LiteralNode","value":"\"hello\"","rb_type":"String"},{"type":"LiteralNode","value":"\"world\"","rb_type":"String"}]],"frozen":false},"var_type":"Var"}|
|
|
86
|
+
Gloss.parse_string(<<-GLS).should eq expected
|
|
87
|
+
hsh : Hash[String, String] = { "hello" => "world" }
|
|
88
|
+
GLS
|
|
89
|
+
end
|
|
120
90
|
|
|
121
|
-
|
|
122
|
-
|
|
91
|
+
# it "parses method calls in case statements" do
|
|
92
|
+
# expected =
|
|
93
|
+
# %q|{"type":"Case","condition":{"type":"LiteralNode","value":"\"abc\"","rb_type":"String"},"whens":[{"type":"When","conditions":[{"type":"Proc","function":{"type":"DefNode","name":"->","body":{"type":"Call","name":"start_with?","args":[{"type":"LiteralNode","value":"\"a\"","rb_type":"String"}],"object":{"type":"Var","name":"x"},"block":null,"block_arg":null},"rp_args":[{"type":"Arg","name":"x","external_name":"x","default_value":null,"restriction":null,"keyword_arg":false}],"receiver":null,"return_type":null,"rest_kw_args":null}}],"body":{"type":"LiteralNode","value":"1","rb_type":"Integer"},"exhaustive":false}],"else":{"type":"LiteralNode","value":"0","rb_type":"Integer"},"exhaustive":false}|
|
|
94
|
+
# Gloss.parse_string(<<-GLS).should eq expected
|
|
95
|
+
# case "abc"
|
|
96
|
+
# when .start_with? 'a'
|
|
97
|
+
# 1
|
|
98
|
+
# else
|
|
99
|
+
# 0
|
|
100
|
+
# end
|
|
101
|
+
# GLS
|
|
102
|
+
# end
|
|
103
|
+
|
|
104
|
+
# it "allows constant methods" do
|
|
105
|
+
# Gloss.parse_string(<<-GLS).should be_truthy
|
|
106
|
+
# def Hello(arg = nil)
|
|
107
|
+
# end
|
|
108
|
+
|
|
109
|
+
# Hello()
|
|
110
|
+
|
|
111
|
+
# Hello("a")
|
|
112
|
+
# GLS
|
|
113
|
+
# end
|
|
114
|
+
|
|
115
|
+
# it "requires constant methods to be called with ()" do
|
|
116
|
+
# Gloss.parse_string(<<-GLS).should be_falsey
|
|
117
|
+
# def Hello(arg = nil)
|
|
118
|
+
# end
|
|
119
|
+
|
|
120
|
+
# Hello
|
|
121
|
+
# GLS
|
|
122
|
+
# end
|
|
123
123
|
end
|
|
124
124
|
end
|
data/ext/gloss/src/cr_ast.cr
CHANGED
|
@@ -140,7 +140,9 @@ module Crystal
|
|
|
140
140
|
|
|
141
141
|
class Block < ASTNode
|
|
142
142
|
def to_rb
|
|
143
|
-
|
|
143
|
+
positional_args = args.dup
|
|
144
|
+
splat = @splat_index ? positional_args.delete_at(@splat_index.as(Int32)) : nil
|
|
145
|
+
Rb::AST::Block.new(positional_args.map(&.to_rb), splat.try &.to_rb, @body.to_rb)
|
|
144
146
|
end
|
|
145
147
|
end
|
|
146
148
|
|
data/ext/gloss/src/rb_ast.cr
CHANGED
|
@@ -43,13 +43,14 @@ module Rb
|
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
class Block < Node
|
|
46
|
-
@info : NamedTuple(type: String,
|
|
46
|
+
@info : NamedTuple(type: String, positional_args: Array(Var), body: Node, rest_p_args: Node?)
|
|
47
47
|
|
|
48
|
-
def initialize(args, body)
|
|
48
|
+
def initialize(args, splat, body)
|
|
49
49
|
@info = {
|
|
50
50
|
type: self.class.name.split("::").last,
|
|
51
51
|
body: body,
|
|
52
|
-
|
|
52
|
+
positional_args: args,
|
|
53
|
+
rest_p_args: splat
|
|
53
54
|
}
|
|
54
55
|
end
|
|
55
56
|
|
data/lib/gloss/builder.rb
CHANGED
|
@@ -3,8 +3,18 @@
|
|
|
3
3
|
##### This file was generated by Gloss; any changes made here will be overwritten.
|
|
4
4
|
##### See src/ to make changes
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
module Gloss
|
|
7
|
+
module Utils
|
|
8
|
+
module_function
|
|
9
|
+
def with_file_header(str)
|
|
10
|
+
"#{Builder::FILE_HEADER}\n\n#{str}"
|
|
11
|
+
end
|
|
12
|
+
end
|
|
7
13
|
class Builder
|
|
14
|
+
FILE_HEADER = " #{(if Config.frozen_string_literals
|
|
15
|
+
"# frozen_string_literal: true\n"
|
|
16
|
+
end)}\n ##### This file was generated by Gloss; any changes made here will be overwritten.\n ##### See #{Config.src_dir}/ to make changes"
|
|
17
|
+
include Utils
|
|
8
18
|
attr_reader(:"tree")
|
|
9
19
|
def initialize(tree_hash, type_checker = nil)
|
|
10
20
|
@indent_level = 0
|
|
@@ -16,9 +26,7 @@
|
|
|
16
26
|
end
|
|
17
27
|
def run()
|
|
18
28
|
rb_output = visit_node(@tree)
|
|
19
|
-
|
|
20
|
-
"# frozen_string_literal: true\n"
|
|
21
|
-
end)}\n ##### This file was generated by Gloss; any changes made here will be overwritten.\n ##### See #{Config.src_dir}/ to make changes\n\n #{rb_output}"
|
|
29
|
+
with_file_header(rb_output)
|
|
22
30
|
end
|
|
23
31
|
def visit_node(node, scope = Scope.new)
|
|
24
32
|
src = Source.new(@indent_level)
|
|
@@ -99,7 +107,7 @@ case node.[](:"type")
|
|
|
99
107
|
src.write_ln("end")
|
|
100
108
|
when "DefNode"
|
|
101
109
|
args = render_args(node)
|
|
102
|
-
src.write_ln("def #{node.[](:"name")}#{args}")
|
|
110
|
+
src.write_ln("def #{node.[](:"name")}#{args.[](:"representation")}")
|
|
103
111
|
return_type = (if node.[](:"return_type")
|
|
104
112
|
RBS::Types::ClassInstance.new(name: RBS::TypeName.new(name: eval(visit_node(node.[](:"return_type")))
|
|
105
113
|
.to_s
|
|
@@ -107,34 +115,7 @@ case node.[](:"type")
|
|
|
107
115
|
else
|
|
108
116
|
RBS::Types::Bases::Any.new(location: node.[](:"location"))
|
|
109
117
|
end)
|
|
110
|
-
|
|
111
|
-
rp = node.fetch(:"positional_args") { ||
|
|
112
|
-
EMPTY_ARRAY }
|
|
113
|
-
.filter() { |a|
|
|
114
|
-
!a.[](:"value") }
|
|
115
|
-
# @type var op: Array[Hash[Symbol, Any]]
|
|
116
|
-
op = node.fetch(:"positional_args") { ||
|
|
117
|
-
EMPTY_ARRAY }
|
|
118
|
-
.filter() { |a|
|
|
119
|
-
a.[](:"value")
|
|
120
|
-
}
|
|
121
|
-
method_types = [RBS::MethodType.new(type_params: EMPTY_ARRAY, type: RBS::Types::Function.new(required_positionals: rp.map() { |a|
|
|
122
|
-
RBS::Types::Function::Param.new(name: visit_node(a)
|
|
123
|
-
.to_sym, type: RBS::Types::Bases::Any.new(location: a.[](:"location")))
|
|
124
|
-
}, optional_positionals: op.map() { |a|
|
|
125
|
-
RBS::Types::Function::Param.new(name: visit_node(a)
|
|
126
|
-
.to_sym, type: RBS::Types::Bases::Any.new(location: a.[](:"location")))
|
|
127
|
-
}, rest_positionals: (if rpa = node.[](:"rest_p_args")
|
|
128
|
-
RBS::Types::Function::Param.new(name: visit_node(rpa)
|
|
129
|
-
.to_sym, type: RBS::Types::Bases::Any.new(location: node.[](:"location")))
|
|
130
|
-
else
|
|
131
|
-
nil
|
|
132
|
-
end), trailing_positionals: EMPTY_ARRAY, required_keywords: node.[](:"req_kw_args") || EMPTY_HASH, optional_keywords: node.[](:"opt_kw_args") || EMPTY_HASH, rest_keywords: (if node.[](:"rest_kw_args")
|
|
133
|
-
RBS::Types::Function::Param.new(name: visit_node(node.[](:"rest_kw_args"))
|
|
134
|
-
.to_sym, type: RBS::Types::Bases::Any.new(location: node.[](:"location")))
|
|
135
|
-
else
|
|
136
|
-
nil
|
|
137
|
-
end), return_type: return_type), block: (if node.[](:"yield_arg_count")
|
|
118
|
+
method_types = [RBS::MethodType.new(type_params: EMPTY_ARRAY, type: RBS::Types::Function.new(required_positionals: args.dig(:"types", :"required_positionals"), optional_positionals: args.dig(:"types", :"optional_positionals"), rest_positionals: args.dig(:"types", :"rest_positionals"), trailing_positionals: args.dig(:"types", :"trailing_positionals"), required_keywords: args.dig(:"types", :"required_keywords"), optional_keywords: args.dig(:"types", :"optional_keywords"), rest_keywords: args.dig(:"types", :"rest_keywords"), return_type: return_type), block: (if node.[](:"yield_arg_count")
|
|
138
119
|
RBS::Types::Block.new(type: RBS::Types::Function.new(required_positionals: Array.new, optional_positionals: Array.new, rest_positionals: nil, trailing_positionals: Array.new, required_keywords: Hash.new, optional_keywords: Hash.new, rest_keywords: nil, return_type: RBS::Types::Bases::Any.new(location: node.[](:"location"))), required: !!node.[](:"block_arg") || node.[](:"yield_arg_count"))
|
|
139
120
|
else
|
|
140
121
|
nil
|
|
@@ -203,11 +184,9 @@ EMPTY_ARRAY }
|
|
|
203
184
|
end)}#{block}"
|
|
204
185
|
src.write_ln(call)
|
|
205
186
|
when "Block"
|
|
206
|
-
|
|
207
|
-
.
|
|
208
|
-
|
|
209
|
-
}
|
|
210
|
-
.join(", ")}|\n")
|
|
187
|
+
args = render_args(node)
|
|
188
|
+
src.write("{ #{args.[](:"representation")
|
|
189
|
+
.gsub(/(\A\(|\)\z)/, "|")}\n")
|
|
211
190
|
indented(src) { ||
|
|
212
191
|
src.write(visit_node(node.[](:"body")))
|
|
213
192
|
}
|
|
@@ -391,7 +370,7 @@ EMPTY_ARRAY }
|
|
|
391
370
|
end
|
|
392
371
|
# @type var expanded: Array[String]
|
|
393
372
|
expanded = eval(visit_node(expr))
|
|
394
|
-
.map() {
|
|
373
|
+
.map() { |*a|
|
|
395
374
|
locals = [var_names.join("\", \"")].zip(a)
|
|
396
375
|
.to_h
|
|
397
376
|
(if @inside_macro
|
|
@@ -538,6 +517,11 @@ EMPTY_ARRAY }
|
|
|
538
517
|
.join(" | ")
|
|
539
518
|
end)
|
|
540
519
|
src.write(output)
|
|
520
|
+
when "Next"
|
|
521
|
+
(if node.[](:"value")
|
|
522
|
+
val = " #{node.[](:"value")}"
|
|
523
|
+
end)
|
|
524
|
+
src.write("next#{val}")
|
|
541
525
|
when "EmptyNode"
|
|
542
526
|
# no op
|
|
543
527
|
else
|
|
@@ -610,7 +594,35 @@ a && a.empty? }
|
|
|
610
594
|
end)].reject(&:"empty?")
|
|
611
595
|
.flatten
|
|
612
596
|
.join(", ")
|
|
613
|
-
"(#{contents})"
|
|
597
|
+
representation = "(#{contents})"
|
|
598
|
+
rp.map!() { |a|
|
|
599
|
+
RBS::Types::Function::Param.new(name: visit_node(a)
|
|
600
|
+
.to_sym, type: RBS::Types::Bases::Any.new(location: a.[](:"location")))
|
|
601
|
+
}
|
|
602
|
+
op.map!() { |a|
|
|
603
|
+
RBS::Types::Function::Param.new(name: visit_node(a)
|
|
604
|
+
.to_sym, type: RBS::Types::Bases::Any.new(location: a.[](:"location")))
|
|
605
|
+
}
|
|
606
|
+
rest_p = (if rpa = node.[](:"rest_p_args")
|
|
607
|
+
RBS::Types::Function::Param.new(name: visit_node(rpa)
|
|
608
|
+
.to_sym, type: RBS::Types::Bases::Any.new(location: node.[](:"location")))
|
|
609
|
+
else
|
|
610
|
+
nil
|
|
611
|
+
end)
|
|
612
|
+
{:representation => representation,
|
|
613
|
+
:types => {:required_positionals => rp,
|
|
614
|
+
:optional_positionals => op,
|
|
615
|
+
:rest_positionals => rest_p,
|
|
616
|
+
:trailing_positionals => EMPTY_ARRAY,
|
|
617
|
+
:required_keywords => node.[](:"req_kw_args") || EMPTY_HASH,
|
|
618
|
+
:optional_keywords => node.[](:"opt_kw_args") || EMPTY_HASH,
|
|
619
|
+
:rest_keywords => (if node.[](:"rest_kw_args")
|
|
620
|
+
RBS::Types::Function::Param.new(name: visit_node(node.[](:"rest_kw_args"))
|
|
621
|
+
.to_sym, type: RBS::Types::Bases::Any.new(location: node.[](:"location")))
|
|
622
|
+
else
|
|
623
|
+
nil
|
|
624
|
+
end)
|
|
625
|
+
}.freeze}.freeze
|
|
614
626
|
end
|
|
615
627
|
end
|
|
616
628
|
end
|
data/lib/gloss/cli.rb
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
##### This file was generated by Gloss; any changes made here will be overwritten.
|
|
4
4
|
##### See src/ to make changes
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
require "optparse"
|
|
7
7
|
module Gloss
|
|
8
8
|
class CLI
|
|
9
9
|
def initialize(argv)
|
|
@@ -12,42 +12,47 @@ module Gloss
|
|
|
12
12
|
def run()
|
|
13
13
|
command = @argv.first
|
|
14
14
|
files = @argv.[]((1..-1))
|
|
15
|
+
err_msg = catch(:"error") { ||
|
|
15
16
|
case command
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
when "watch"
|
|
18
|
+
Watcher.new(files)
|
|
18
19
|
.watch
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
when "build"
|
|
21
|
+
(if files.empty?
|
|
22
|
+
Dir.glob("#{Config.src_dir}/**/*.gl")
|
|
23
|
+
else
|
|
24
|
+
files
|
|
25
|
+
end)
|
|
25
26
|
.each() { |fp|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
puts("=====> Building #{fp}")
|
|
28
|
+
content = File.read(fp)
|
|
29
|
+
tree_hash = Parser.new(content)
|
|
29
30
|
.run
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
type_checker = TypeChecker.new
|
|
32
|
+
rb_output = Builder.new(tree_hash, type_checker)
|
|
32
33
|
.run
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
type_checker.run(rb_output)
|
|
35
|
+
puts("=====> Writing #{fp}")
|
|
36
|
+
Writer.new(rb_output, fp)
|
|
36
37
|
.run
|
|
37
|
-
}
|
|
38
|
-
when "init"
|
|
39
|
-
force = false
|
|
40
|
-
OptionParser.new() { |opt|
|
|
41
|
-
opt.on("--force", "-f") { ||
|
|
42
|
-
force = true
|
|
43
38
|
}
|
|
44
|
-
|
|
39
|
+
when "init"
|
|
40
|
+
force = false
|
|
41
|
+
OptionParser.new() { |opt|
|
|
42
|
+
opt.on("--force", "-f") { ||
|
|
43
|
+
force = true
|
|
44
|
+
}
|
|
45
|
+
}
|
|
45
46
|
.parse(@argv)
|
|
46
|
-
|
|
47
|
+
Initializer.new(force)
|
|
47
48
|
.run
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
else
|
|
50
|
+
throw(:"error", "Gloss doesn't know how to #{command}")
|
|
51
|
+
end
|
|
52
|
+
nil }
|
|
53
|
+
(if err_msg
|
|
54
|
+
abort(err_msg)
|
|
55
|
+
end)
|
|
51
56
|
end
|
|
52
57
|
end
|
|
53
58
|
end
|
data/lib/gloss/config.rb
CHANGED
|
@@ -3,12 +3,17 @@
|
|
|
3
3
|
##### This file was generated by Gloss; any changes made here will be overwritten.
|
|
4
4
|
##### See src/ to make changes
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
require "ostruct"
|
|
7
7
|
require "yaml"
|
|
8
8
|
module Gloss
|
|
9
|
-
|
|
9
|
+
CONFIG_PATH = ".gloss.yml"
|
|
10
10
|
Config = OpenStruct.new(default_config: {:frozen_string_literals => true,
|
|
11
11
|
:src_dir => "src"}.freeze)
|
|
12
|
+
user_config = (if File.exist?(CONFIG_PATH)
|
|
13
|
+
YAML.safe_load(File.read(CONFIG_PATH))
|
|
14
|
+
else
|
|
15
|
+
Config.default_config
|
|
16
|
+
end)
|
|
12
17
|
Config.default_config
|
|
13
18
|
.each() { |k, v|
|
|
14
19
|
Config.send(:"#{k}=", user_config.[](k.to_s) || v)
|
data/lib/gloss/initializer.rb
CHANGED
|
@@ -3,22 +3,22 @@
|
|
|
3
3
|
##### This file was generated by Gloss; any changes made here will be overwritten.
|
|
4
4
|
##### See src/ to make changes
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
require "yaml"
|
|
7
7
|
module Gloss
|
|
8
8
|
class Initializer
|
|
9
9
|
def initialize(force)
|
|
10
10
|
@force = force
|
|
11
11
|
end
|
|
12
12
|
def run()
|
|
13
|
-
(if File.exist?(
|
|
14
|
-
|
|
13
|
+
(if File.exist?(CONFIG_PATH) && !@force
|
|
14
|
+
throw(:"error", "#{CONFIG_PATH} file already exists - aborting. Use --force to override.")
|
|
15
15
|
end)
|
|
16
|
-
File.open(
|
|
16
|
+
File.open(CONFIG_PATH, "wb") { |file|
|
|
17
17
|
file.puts(Config.default_config
|
|
18
18
|
.transform_keys(&:"to_s")
|
|
19
19
|
.to_yaml)
|
|
20
20
|
}
|
|
21
|
-
puts("Created
|
|
21
|
+
puts("Created #{CONFIG_PATH} with default preferences")
|
|
22
22
|
end
|
|
23
23
|
end
|
|
24
24
|
end
|
data/lib/gloss/version.rb
CHANGED
data/lib/gloss/watcher.rb
CHANGED
|
@@ -6,24 +6,38 @@
|
|
|
6
6
|
require "listen"
|
|
7
7
|
module Gloss
|
|
8
8
|
class Watcher
|
|
9
|
-
def initialize()
|
|
10
|
-
@paths =
|
|
9
|
+
def initialize(paths)
|
|
10
|
+
@paths = paths
|
|
11
|
+
(if @paths.empty?
|
|
12
|
+
@paths = [File.join(Dir.pwd, Config.src_dir)]
|
|
13
|
+
end)
|
|
11
14
|
end
|
|
12
15
|
def watch()
|
|
13
16
|
puts("=====> Now listening for changes in #{@paths.join(", ")}")
|
|
14
17
|
listener = Listen.to(*@paths, latency: 2) { |modified, added, removed|
|
|
15
18
|
modified.+(added)
|
|
16
19
|
.each() { |f|
|
|
20
|
+
unless f.end_with?(".gl")
|
|
21
|
+
next
|
|
22
|
+
end
|
|
23
|
+
puts("====> Rewriting #{f}")
|
|
17
24
|
content = File.read(f)
|
|
18
|
-
Writer.new(Builder.new(content)
|
|
25
|
+
Writer.new(Builder.new(Parser.new(content)
|
|
26
|
+
.run)
|
|
19
27
|
.run, f)
|
|
20
28
|
.run
|
|
29
|
+
puts("====> Done")
|
|
21
30
|
}
|
|
22
31
|
removed.each() { |f|
|
|
32
|
+
unless f.end_with?(".gl")
|
|
33
|
+
next
|
|
34
|
+
end
|
|
23
35
|
out_path = Utils.src_path_to_output_path(f)
|
|
36
|
+
puts("====> Removing #{out_path}")
|
|
24
37
|
(if File.exist?(out_path)
|
|
25
38
|
File.delete(out_path)
|
|
26
39
|
end)
|
|
40
|
+
puts("====> Done")
|
|
27
41
|
}
|
|
28
42
|
}
|
|
29
43
|
listener.start
|
data/lib/gloss/writer.rb
CHANGED
|
@@ -9,7 +9,7 @@ module Gloss
|
|
|
9
9
|
module Utils
|
|
10
10
|
module_function
|
|
11
11
|
def src_path_to_output_path(src_path)
|
|
12
|
-
src_path.sub(
|
|
12
|
+
src_path.sub("#{Config.src_dir}/", "")
|
|
13
13
|
.sub(/\.gl$/, ".rb")
|
|
14
14
|
end
|
|
15
15
|
end
|
|
@@ -25,7 +25,7 @@ module Gloss
|
|
|
25
25
|
FileUtils.mkdir_p(@output_path.parent)
|
|
26
26
|
end
|
|
27
27
|
File.open(@output_path, "wb") { |file|
|
|
28
|
-
file
|
|
28
|
+
file.puts(@content)
|
|
29
29
|
}
|
|
30
30
|
end
|
|
31
31
|
end
|
data/src/lib/gloss/builder.gl
CHANGED
|
@@ -1,7 +1,21 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
1
|
module Gloss
|
|
2
|
+
module Utils
|
|
3
|
+
module_function
|
|
4
|
+
|
|
5
|
+
def with_file_header(str)
|
|
6
|
+
"#{Builder::FILE_HEADER}\n\n#{str}"
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
4
10
|
class Builder
|
|
11
|
+
FILE_HEADER = <<~RUBY
|
|
12
|
+
#{"# frozen_string_literal: true\n" if Config.frozen_string_literals}
|
|
13
|
+
##### This file was generated by Gloss; any changes made here will be overwritten.
|
|
14
|
+
##### See #{Config.src_dir}/ to make changes
|
|
15
|
+
RUBY
|
|
16
|
+
|
|
17
|
+
include Utils
|
|
18
|
+
|
|
5
19
|
attr_reader :tree
|
|
6
20
|
|
|
7
21
|
def initialize(tree_hash, type_checker = nil)
|
|
@@ -15,13 +29,7 @@ module Gloss
|
|
|
15
29
|
|
|
16
30
|
def run
|
|
17
31
|
rb_output = visit_node(@tree)
|
|
18
|
-
|
|
19
|
-
#{"# frozen_string_literal: true\n" if Config.frozen_string_literals}
|
|
20
|
-
##### This file was generated by Gloss; any changes made here will be overwritten.
|
|
21
|
-
##### See #{Config.src_dir}/ to make changes
|
|
22
|
-
|
|
23
|
-
#{rb_output}
|
|
24
|
-
RUBY
|
|
32
|
+
with_file_header(rb_output)
|
|
25
33
|
end
|
|
26
34
|
|
|
27
35
|
# type node = Hash[Symbol, String | Array[String | node] | Hash[Symbol, node]] | true | false
|
|
@@ -105,7 +113,7 @@ module Gloss
|
|
|
105
113
|
src.write_ln "end"
|
|
106
114
|
when "DefNode"
|
|
107
115
|
args = render_args(node)
|
|
108
|
-
src.write_ln "def #{node[:name]}#{args}"
|
|
116
|
+
src.write_ln "def #{node[:name]}#{args[:representation]}"
|
|
109
117
|
|
|
110
118
|
return_type = if node[:return_type]
|
|
111
119
|
RBS::Types::ClassInstance.new(
|
|
@@ -122,36 +130,17 @@ module Gloss
|
|
|
122
130
|
)
|
|
123
131
|
end
|
|
124
132
|
|
|
125
|
-
rp : Array[Hash[Symbol, Any]] = node.fetch(:positional_args) { EMPTY_ARRAY }.filter { |a| !a[:value] }
|
|
126
|
-
op : Array[Hash[Symbol, Any]] = node.fetch(:positional_args) { EMPTY_ARRAY }.filter { |a| a[:value] }
|
|
127
|
-
|
|
128
133
|
method_types = [
|
|
129
134
|
RBS::MethodType.new(
|
|
130
135
|
type_params: EMPTY_ARRAY, # TODO
|
|
131
136
|
type: RBS::Types::Function.new(
|
|
132
|
-
required_positionals:
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
end,
|
|
140
|
-
optional_positionals: op.map do |a|
|
|
141
|
-
RBS::Types::Function::Param.new(
|
|
142
|
-
name: visit_node(a).to_sym,
|
|
143
|
-
type: RBS::Types::Bases::Any.new(location: a[:location])
|
|
144
|
-
)
|
|
145
|
-
end,
|
|
146
|
-
rest_positionals: (rpa = node[:rest_p_args]) ? RBS::Types::Function::Param.new(name: visit_node(rpa).to_sym, type: RBS::Types::Bases::Any.new(location: node[:location])) : nil,
|
|
147
|
-
trailing_positionals: EMPTY_ARRAY, # TODO
|
|
148
|
-
required_keywords: node[:req_kw_args] || EMPTY_HASH,
|
|
149
|
-
optional_keywords: node[:opt_kw_args] || EMPTY_HASH,
|
|
150
|
-
rest_keywords: node[:rest_kw_args] ?
|
|
151
|
-
RBS::Types::Function::Param.new(
|
|
152
|
-
name: visit_node(node[:rest_kw_args]).to_sym,
|
|
153
|
-
type: RBS::Types::Bases::Any.new(location: node[:location])
|
|
154
|
-
) : nil,
|
|
137
|
+
required_positionals: args.dig(:types, :required_positionals),
|
|
138
|
+
optional_positionals: args.dig(:types, :optional_positionals),
|
|
139
|
+
rest_positionals: args.dig(:types, :rest_positionals),
|
|
140
|
+
trailing_positionals: args.dig(:types, :trailing_positionals),
|
|
141
|
+
required_keywords: args.dig(:types, :required_keywords),
|
|
142
|
+
optional_keywords: args.dig(:types, :optional_keywords),
|
|
143
|
+
rest_keywords: args.dig(:types, :rest_keywords),
|
|
155
144
|
return_type: return_type
|
|
156
145
|
),
|
|
157
146
|
block: node[:yield_arg_count] ?
|
|
@@ -216,8 +205,8 @@ module Gloss
|
|
|
216
205
|
src.write_ln(call)
|
|
217
206
|
|
|
218
207
|
when "Block"
|
|
219
|
-
|
|
220
|
-
src.write "{
|
|
208
|
+
args = render_args node
|
|
209
|
+
src.write "{ #{args[:representation].gsub(/(\A\(|\)\z)/,'|')}\n"
|
|
221
210
|
|
|
222
211
|
indented(src) { src.write visit_node(node[:body]) }
|
|
223
212
|
|
|
@@ -466,6 +455,9 @@ module Gloss
|
|
|
466
455
|
types.map { |t| visit_node(t) }.join(" | ")
|
|
467
456
|
end
|
|
468
457
|
src.write output
|
|
458
|
+
when "Next"
|
|
459
|
+
val = " #{node[:value]}" if node[:value]
|
|
460
|
+
src.write "next#{val}"
|
|
469
461
|
when "EmptyNode"
|
|
470
462
|
# pass
|
|
471
463
|
else
|
|
@@ -497,7 +489,8 @@ module Gloss
|
|
|
497
489
|
src.decrement_indent
|
|
498
490
|
end
|
|
499
491
|
|
|
500
|
-
|
|
492
|
+
# TODO: allow NamedTuple as return type
|
|
493
|
+
private def render_args(node)# : { representation: String, types: Hash[Symbol, Any] }
|
|
501
494
|
rp : Array[Hash[Symbol, Any]] = node.fetch(:positional_args) { EMPTY_ARRAY }.filter { |a| !a[:value] }
|
|
502
495
|
op : Array[Hash[Symbol, Any]] = node.fetch(:positional_args) { EMPTY_ARRAY }.filter { |a| a[:value] }
|
|
503
496
|
rkw : Hash[Symbol, Any] = node.fetch(:req_kw_args) { EMPTY_HASH }
|
|
@@ -514,7 +507,38 @@ module Gloss
|
|
|
514
507
|
rest_p ? "*#{rest_p}" : "",
|
|
515
508
|
rest_kw ? "**#{visit_node(rest_kw)}" : ""
|
|
516
509
|
].reject(&:empty?).flatten.join(", ")
|
|
517
|
-
"(#{contents})"
|
|
510
|
+
representation = "(#{contents})"
|
|
511
|
+
rp.map! do |a|
|
|
512
|
+
RBS::Types::Function::Param.new(
|
|
513
|
+
name: visit_node(a).to_sym,
|
|
514
|
+
type: RBS::Types::Bases::Any.new(
|
|
515
|
+
location: a[:location]
|
|
516
|
+
)
|
|
517
|
+
)
|
|
518
|
+
end
|
|
519
|
+
op.map! do |a|
|
|
520
|
+
RBS::Types::Function::Param.new(
|
|
521
|
+
name: visit_node(a).to_sym,
|
|
522
|
+
type: RBS::Types::Bases::Any.new(location: a[:location])
|
|
523
|
+
)
|
|
524
|
+
end
|
|
525
|
+
rest_p = (rpa = node[:rest_p_args]) ? RBS::Types::Function::Param.new(name: visit_node(rpa).to_sym, type: RBS::Types::Bases::Any.new(location: node[:location])) : nil
|
|
526
|
+
{
|
|
527
|
+
representation: representation,
|
|
528
|
+
types: {
|
|
529
|
+
required_positionals: rp,
|
|
530
|
+
optional_positionals: op,
|
|
531
|
+
rest_positionals: rest_p,
|
|
532
|
+
trailing_positionals: EMPTY_ARRAY, # TODO
|
|
533
|
+
required_keywords: node[:req_kw_args] || EMPTY_HASH,
|
|
534
|
+
optional_keywords: node[:opt_kw_args] || EMPTY_HASH,
|
|
535
|
+
rest_keywords: node[:rest_kw_args] ?
|
|
536
|
+
RBS::Types::Function::Param.new(
|
|
537
|
+
name: visit_node(node[:rest_kw_args]).to_sym,
|
|
538
|
+
type: RBS::Types::Bases::Any.new(location: node[:location])
|
|
539
|
+
) : nil
|
|
540
|
+
}
|
|
541
|
+
}
|
|
518
542
|
end
|
|
519
543
|
end
|
|
520
544
|
end
|
data/src/lib/gloss/cli.gl
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
1
|
require "optparse"
|
|
4
2
|
|
|
5
3
|
module Gloss
|
|
@@ -12,30 +10,35 @@ module Gloss
|
|
|
12
10
|
# TODO: allow destructuring: command, *files = @argv
|
|
13
11
|
command = @argv.first
|
|
14
12
|
files = @argv[1..-1]
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
13
|
+
err_msg = catch :error do
|
|
14
|
+
case command
|
|
15
|
+
when "watch"
|
|
16
|
+
Watcher.new(files).watch
|
|
17
|
+
when "build"
|
|
18
|
+
(files.empty? ? Dir.glob("#{Config.src_dir}/**/*.gl") : files).each do |fp|
|
|
19
|
+
puts "=====> Building #{fp}"
|
|
20
|
+
content = File.read(fp)
|
|
21
|
+
tree_hash = Parser.new(content).run
|
|
22
|
+
type_checker = TypeChecker.new
|
|
23
|
+
rb_output = Builder.new(tree_hash, type_checker).run
|
|
24
|
+
type_checker.run(rb_output)
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
puts "=====> Writing #{fp}"
|
|
27
|
+
Writer.new(rb_output, fp).run
|
|
28
|
+
end
|
|
29
|
+
when "init"
|
|
30
|
+
force = false
|
|
31
|
+
OptionParser.new do |opt|
|
|
32
|
+
opt.on("--force", "-f") { force = true }
|
|
33
|
+
end.parse(@argv)
|
|
34
|
+
Initializer.new(force).run
|
|
35
|
+
else
|
|
36
|
+
throw :error, "Gloss doesn't know how to #{command}"
|
|
29
37
|
end
|
|
30
|
-
|
|
31
|
-
force = false
|
|
32
|
-
OptionParser.new do |opt|
|
|
33
|
-
opt.on("--force", "-f") { force = true }
|
|
34
|
-
end.parse(@argv)
|
|
35
|
-
Initializer.new(force).run
|
|
36
|
-
else
|
|
37
|
-
abort "Gloss doesn't know how to #{command}"
|
|
38
|
+
nil
|
|
38
39
|
end
|
|
40
|
+
|
|
41
|
+
abort err_msg if err_msg
|
|
39
42
|
end
|
|
40
43
|
end
|
|
41
44
|
end
|
data/src/lib/gloss/config.gl
CHANGED
|
@@ -4,12 +4,18 @@ require "ostruct"
|
|
|
4
4
|
require "yaml"
|
|
5
5
|
|
|
6
6
|
module Gloss
|
|
7
|
-
|
|
7
|
+
CONFIG_PATH = ".gloss.yml"
|
|
8
8
|
Config = OpenStruct.new(
|
|
9
9
|
default_config: {
|
|
10
10
|
frozen_string_literals: true,
|
|
11
11
|
src_dir: "src",
|
|
12
12
|
}
|
|
13
13
|
)
|
|
14
|
+
|
|
15
|
+
user_config = if File.exist?(CONFIG_PATH)
|
|
16
|
+
YAML.safe_load(File.read(CONFIG_PATH))
|
|
17
|
+
else
|
|
18
|
+
Config.default_config
|
|
19
|
+
end
|
|
14
20
|
Config.default_config.each { |k, v| Config.send(:"#{k}=", user_config[k.to_s] || v) }
|
|
15
21
|
end
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
1
|
require "yaml"
|
|
4
2
|
|
|
5
3
|
module Gloss
|
|
@@ -8,15 +6,15 @@ module Gloss
|
|
|
8
6
|
end
|
|
9
7
|
|
|
10
8
|
def run
|
|
11
|
-
if File.exist?(
|
|
12
|
-
|
|
9
|
+
if File.exist?(CONFIG_PATH) && !@force
|
|
10
|
+
throw :error, "#{CONFIG_PATH} file already exists - aborting. Use --force to override."
|
|
13
11
|
end
|
|
14
12
|
|
|
15
|
-
File.open(
|
|
13
|
+
File.open(CONFIG_PATH, "wb") do |file|
|
|
16
14
|
file.puts Config.default_config.transform_keys(&:to_s).to_yaml
|
|
17
15
|
end
|
|
18
16
|
|
|
19
|
-
puts "Created
|
|
17
|
+
puts "Created #{CONFIG_PATH} with default preferences"
|
|
20
18
|
end
|
|
21
19
|
end
|
|
22
20
|
end
|
data/src/lib/gloss/version.gl
CHANGED
data/src/lib/gloss/watcher.gl
CHANGED
|
@@ -4,20 +4,36 @@ require "listen"
|
|
|
4
4
|
|
|
5
5
|
module Gloss
|
|
6
6
|
class Watcher
|
|
7
|
-
def initialize
|
|
8
|
-
@paths =
|
|
7
|
+
def initialize(@paths : Array[String])
|
|
8
|
+
@paths = [File.join(Dir.pwd, Config.src_dir)] if @paths.empty?
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def watch
|
|
12
12
|
puts "=====> Now listening for changes in #{@paths.join(', ')}"
|
|
13
13
|
listener = Listen.to(*@paths, latency: 2) do |modified, added, removed|
|
|
14
14
|
(modified + added).each do |f|
|
|
15
|
+
next unless f.end_with? ".gl"
|
|
16
|
+
|
|
17
|
+
puts "====> Rewriting #{f}"
|
|
15
18
|
content = File.read(f)
|
|
16
|
-
Writer.new(
|
|
19
|
+
Writer.new(
|
|
20
|
+
Builder.new(
|
|
21
|
+
Parser.new(
|
|
22
|
+
content
|
|
23
|
+
).run
|
|
24
|
+
).run, f
|
|
25
|
+
).run
|
|
26
|
+
|
|
27
|
+
puts "====> Done"
|
|
17
28
|
end
|
|
18
29
|
removed.each do |f|
|
|
30
|
+
next unless f.end_with? ".gl"
|
|
31
|
+
|
|
19
32
|
out_path = Utils.src_path_to_output_path(f)
|
|
33
|
+
puts "====> Removing #{out_path}"
|
|
20
34
|
File.delete out_path if File.exist? out_path
|
|
35
|
+
|
|
36
|
+
puts "====> Done"
|
|
21
37
|
end
|
|
22
38
|
end
|
|
23
39
|
listener.start
|
data/src/lib/gloss/writer.gl
CHANGED
|
@@ -8,7 +8,7 @@ module Gloss
|
|
|
8
8
|
module_function
|
|
9
9
|
|
|
10
10
|
def src_path_to_output_path(src_path : String) : String
|
|
11
|
-
src_path.sub(
|
|
11
|
+
src_path.sub("#{Config.src_dir}/", "")
|
|
12
12
|
.sub(/\.gl$/, ".rb")
|
|
13
13
|
end
|
|
14
14
|
end
|
|
@@ -26,7 +26,7 @@ module Gloss
|
|
|
26
26
|
def run
|
|
27
27
|
FileUtils.mkdir_p(@output_path.parent) unless @output_path.parent.exist?
|
|
28
28
|
File.open(@output_path, "wb") do |file|
|
|
29
|
-
file
|
|
29
|
+
file.puts @content
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
32
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gloss
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- johansenja
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2021-01-
|
|
11
|
+
date: 2021-01-31 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: fast_blank
|
|
@@ -135,6 +135,7 @@ files:
|
|
|
135
135
|
- ".github/workflows/ruby.yml"
|
|
136
136
|
- ".gitignore"
|
|
137
137
|
- ".gloss.yml"
|
|
138
|
+
- ".rspec"
|
|
138
139
|
- ".rubocop.yml"
|
|
139
140
|
- Gemfile
|
|
140
141
|
- Gemfile.lock
|
|
@@ -202,7 +203,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
202
203
|
- !ruby/object:Gem::Version
|
|
203
204
|
version: '0'
|
|
204
205
|
requirements: []
|
|
205
|
-
rubygems_version: 3.2
|
|
206
|
+
rubygems_version: 3.1.2
|
|
206
207
|
signing_key:
|
|
207
208
|
specification_version: 4
|
|
208
209
|
summary: A superset of ruby
|