gloss 0.0.4 → 0.1.2

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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +3 -0
  3. data/.github/workflows/{crystal.yml → crystal_specs.yml} +1 -1
  4. data/.github/workflows/{ruby.yml → ruby_specs.yml} +2 -2
  5. data/.gloss.yml +1 -0
  6. data/.rspec +1 -0
  7. data/Gemfile.lock +9 -11
  8. data/README.md +35 -5
  9. data/Rakefile +1 -1
  10. data/exe/gloss +13 -2
  11. data/ext/gloss/Makefile +8 -19
  12. data/ext/gloss/spec/parser_spec.cr +83 -83
  13. data/ext/gloss/src/cr_ast.cr +63 -77
  14. data/ext/gloss/src/gloss.cr +1 -2
  15. data/ext/gloss/src/rb_ast.cr +40 -38
  16. data/lib/gloss.rb +15 -7
  17. data/lib/gloss/cli.rb +75 -32
  18. data/lib/gloss/config.rb +10 -3
  19. data/lib/gloss/errors.rb +1 -1
  20. data/lib/gloss/initializer.rb +6 -5
  21. data/lib/gloss/logger.rb +29 -0
  22. data/lib/gloss/parser.rb +17 -2
  23. data/lib/gloss/prog_loader.rb +141 -0
  24. data/lib/gloss/scope.rb +1 -1
  25. data/lib/gloss/source.rb +1 -1
  26. data/lib/gloss/type_checker.rb +80 -32
  27. data/lib/gloss/utils.rb +44 -0
  28. data/lib/gloss/version.rb +5 -5
  29. data/lib/gloss/{builder.rb → visitor.rb} +125 -74
  30. data/lib/gloss/watcher.rb +47 -11
  31. data/lib/gloss/writer.rb +22 -11
  32. data/sig/core.rbs +2 -0
  33. data/sig/fast_blank.rbs +4 -0
  34. data/sig/{gloss.rbs → gls.rbs} +0 -0
  35. data/sig/optparse.rbs +6 -0
  36. data/sig/rubygems.rbs +9 -0
  37. data/sig/yaml.rbs +3 -0
  38. data/src/exe/gloss +19 -0
  39. data/src/lib/gloss.gl +26 -0
  40. data/src/lib/gloss/cli.gl +53 -24
  41. data/src/lib/gloss/config.gl +9 -3
  42. data/src/lib/gloss/initializer.gl +4 -6
  43. data/src/lib/gloss/logger.gl +21 -0
  44. data/src/lib/gloss/parser.gl +17 -5
  45. data/src/lib/gloss/prog_loader.gl +133 -0
  46. data/src/lib/gloss/scope.gl +0 -2
  47. data/src/lib/gloss/type_checker.gl +85 -39
  48. data/src/lib/gloss/utils.gl +38 -0
  49. data/src/lib/gloss/version.gl +1 -1
  50. data/src/lib/gloss/{builder.gl → visitor.gl} +123 -68
  51. data/src/lib/gloss/watcher.gl +44 -10
  52. data/src/lib/gloss/writer.gl +16 -14
  53. metadata +23 -8
data/lib/gloss/version.rb CHANGED
@@ -1,8 +1,8 @@
1
- # frozen_string_literal: true
1
+ # frozen_string_literal: true
2
2
 
3
- ##### This file was generated by Gloss; any changes made here will be overwritten.
4
- ##### See src/ to make changes
3
+ ##### This file was generated by Gloss; any changes made here will be overwritten.
4
+ ##### See src/ to make changes
5
5
 
6
- module Gloss
7
- VERSION = "0.0.4"
6
+ module Gloss
7
+ VERSION = "0.1.2"
8
8
  end
@@ -3,22 +3,25 @@
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
- module Gloss
7
- class Builder
6
+ module Gloss
7
+ class Visitor
8
+ FILE_HEADER = " #{(if Config.frozen_string_literals
9
+ "# frozen_string_literal: true\n"
10
+ end)}\n ##### This file was generated by Gloss; any changes made here will be overwritten.\n ##### See #{Config.src_dir}/ to make changes"
8
11
  attr_reader(:"tree")
9
- def initialize(tree_hash, type_checker = nil)
12
+ def initialize(tree_hash, type_checker = nil, on_new_file_referenced = nil)
13
+ @on_new_file_referenced = on_new_file_referenced
10
14
  @indent_level = 0
11
15
  @inside_macro = false
12
16
  @eval_vars = false
13
17
  @current_scope = nil
14
18
  @tree = tree_hash
15
19
  @type_checker = type_checker
20
+ @after_module_function = false
16
21
  end
17
22
  def run()
18
23
  rb_output = visit_node(@tree)
19
- " #{(if Config.frozen_string_literals
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}"
24
+ Utils.with_file_header(rb_output)
22
25
  end
23
26
  def visit_node(node, scope = Scope.new)
24
27
  src = Source.new(@indent_level)
@@ -32,21 +35,30 @@ case node.[](:"type")
32
35
  RBS::Namespace.root
33
36
  end)
34
37
  superclass_type = nil
35
- superclass_output = nil
38
+ superclass_output = ""
36
39
  (if node.[](:"superclass")
37
40
  @eval_vars = true
38
41
  superclass_output = visit_node(node.[](:"superclass"))
39
42
  @eval_vars = false
40
- superclass_type = RBS::Parser.parse_type(superclass_output)
43
+ args = Array.new
41
44
  (if node.dig(:"superclass", :"type")
42
45
  .==("Generic")
43
- superclass_output = superclass_output.[](/^[^\[]+/)
46
+ superclass_output = superclass_output.[](/^[^\[]+/) || superclass_output
47
+ args = node.dig(:"superclass", :"args")
48
+ .map() { |n|
49
+ RBS::Parser.parse_type(visit_node(n))
50
+ }
44
51
  end)
52
+ class_name_index = superclass_output.index(/[^(?:::)]+\z/) || 0
53
+ namespace = superclass_output.[](0, class_name_index)
54
+ superclass_name = superclass_output.[](/[^(?:::)]+\z/) || superclass_output
55
+ superclass_type = RBS::AST::Declarations::Class::Super.new(name: RBS::TypeName.new(namespace: method(:"Namespace")
56
+ .call(namespace), name: superclass_name.to_sym), args: args, location: build_location(node))
45
57
  end)
46
- src.write_ln("class #{class_name}#{(if superclass_output
58
+ src.write_ln("class #{class_name}#{unless superclass_output.blank?
47
59
  " < #{superclass_output}"
48
- end)}")
49
- class_type = RBS::AST::Declarations::Class.new(name: RBS::TypeName.new(namespace: current_namespace, name: class_name.to_sym), type_params: RBS::AST::Declarations::ModuleTypeParams.new, super_class: superclass_type, members: Array.new, annotations: Array.new, location: node.[](:"location"), comment: node.[](:"comment"))
60
+ end}")
61
+ class_type = RBS::AST::Declarations::Class.new(name: RBS::TypeName.new(namespace: current_namespace, name: class_name.to_sym), type_params: RBS::AST::Declarations::ModuleTypeParams.new, super_class: superclass_type, members: Array.new, annotations: Array.new, location: build_location(node), comment: node.[](:"comment"))
50
62
  old_parent_scope = @current_scope
51
63
  @current_scope = class_type
52
64
  indented(src) { ||
@@ -60,14 +72,13 @@ case node.[](:"type")
60
72
  @current_scope.members
61
73
  .<<(class_type)
62
74
  end)
63
- (if @type_checker
64
- unless @current_scope
65
- @type_checker.top_level_decls
66
- .[]=(class_type.name
67
- .name, class_type)
68
- end
75
+ (if @type_checker && !@current_scope
76
+ @type_checker.top_level_decls
77
+ .add(class_type)
69
78
  end)
70
79
  when "ModuleNode"
80
+ existing_module_function_state = @after_module_function.dup
81
+ @after_module_function = false
71
82
  module_name = visit_node(node.[](:"name"))
72
83
  src.write_ln("module #{module_name}")
73
84
  current_namespace = (if @current_scope
@@ -76,7 +87,7 @@ case node.[](:"type")
76
87
  else
77
88
  RBS::Namespace.root
78
89
  end)
79
- module_type = RBS::AST::Declarations::Module.new(name: RBS::TypeName.new(namespace: current_namespace, name: module_name.to_sym), type_params: RBS::AST::Declarations::ModuleTypeParams.new, self_types: Array.new, members: Array.new, annotations: Array.new, location: node.[](:"location"), comment: node.[](:"comment"))
90
+ module_type = RBS::AST::Declarations::Module.new(name: RBS::TypeName.new(namespace: current_namespace, name: module_name.to_sym), type_params: RBS::AST::Declarations::ModuleTypeParams.new, self_types: Array.new, members: Array.new, annotations: Array.new, location: build_location(node), comment: node.[](:"comment"))
80
91
  old_parent_scope = @current_scope
81
92
  @current_scope = module_type
82
93
  indented(src) { ||
@@ -89,58 +100,44 @@ case node.[](:"type")
89
100
  @current_scope.members
90
101
  .<<(module_type)
91
102
  end)
92
- (if @type_checker
93
- unless @current_scope
94
- @type_checker.top_level_decls
95
- .[]=(module_type.name
96
- .name, module_type)
97
- end
103
+ (if @type_checker && !@current_scope
104
+ @type_checker.top_level_decls
105
+ .add(module_type)
98
106
  end)
99
107
  src.write_ln("end")
108
+ @after_module_function = existing_module_function_state
100
109
  when "DefNode"
101
110
  args = render_args(node)
102
- src.write_ln("def #{node.[](:"name")}#{args}")
111
+ receiver = (if node.[](:"receiver")
112
+ visit_node(node.[](:"receiver"))
113
+ else
114
+ nil
115
+ end)
116
+ src.write_ln("def #{(if receiver
117
+ "#{receiver}."
118
+ end)}#{node.[](:"name")}#{args.[](:"representation")}")
103
119
  return_type = (if node.[](:"return_type")
104
120
  RBS::Types::ClassInstance.new(name: RBS::TypeName.new(name: eval(visit_node(node.[](:"return_type")))
105
121
  .to_s
106
- .to_sym, namespace: RBS::Namespace.root), args: EMPTY_ARRAY, location: node.[](:"location"))
122
+ .to_sym, namespace: RBS::Namespace.root), args: EMPTY_ARRAY, location: build_location(node))
107
123
  else
108
- RBS::Types::Bases::Any.new(location: node.[](:"location"))
124
+ RBS::Types::Bases::Any.new(location: build_location(node))
109
125
  end)
110
- # @type var rp: Array[Hash[Symbol, Any]]
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")
138
- 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"))
126
+ 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")
127
+ 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: build_location(node))), required: !!node.[](:"block_arg") || node.[](:"yield_arg_count"))
139
128
  else
140
129
  nil
141
- end), location: node.[](:"location"))]
130
+ end), location: build_location(node))]
142
131
  method_definition = RBS::AST::Members::MethodDefinition.new(name: node.[](:"name")
143
- .to_sym, kind: :"instance", types: method_types, annotations: EMPTY_ARRAY, location: node.[](:"location"), comment: node.[](:"comment"), overload: false)
132
+ .to_sym, kind: (if @after_module_function
133
+ :"singleton_instance"
134
+ else
135
+ (if receiver
136
+ :"singleton"
137
+ else
138
+ :"instance"
139
+ end)
140
+ end), types: method_types, annotations: EMPTY_ARRAY, location: build_location(node), comment: node.[](:"comment"), overload: false)
144
141
  (if @current_scope
145
142
  @current_scope.members
146
143
  .<<(method_definition)
@@ -198,16 +195,23 @@ EMPTY_ARRAY }
198
195
  else
199
196
  nil
200
197
  end)
201
- call = "#{obj}#{node.[](:"name")}#{opening_delimiter}#{args}#{(if has_parens
198
+ name = node.[](:"name")
199
+ call = "#{obj}#{name}#{opening_delimiter}#{args}#{(if has_parens
202
200
  ")"
203
201
  end)}#{block}"
202
+ case name
203
+ when "require_relative"
204
+ (if @on_new_file_referenced
205
+ @on_new_file_referenced.call(name, true)
206
+ end)
207
+ when "module_function"
208
+ @after_module_function = true
209
+ end
204
210
  src.write_ln(call)
205
211
  when "Block"
206
- src.write("{ |#{node.[](:"args")
207
- .map() { |a|
208
- visit_node(a)
209
- }
210
- .join(", ")}|\n")
212
+ args = render_args(node)
213
+ src.write("{ #{args.[](:"representation")
214
+ .gsub(/(\A\(|\)\z)/, "|")}\n")
211
215
  indented(src) { ||
212
216
  src.write(visit_node(node.[](:"body")))
213
217
  }
@@ -218,7 +222,7 @@ EMPTY_ARRAY }
218
222
  else
219
223
  ".."
220
224
  end)
221
- src.write("(", visit_node(node.[](:"from")), dots, visit_node(node.[](:"to")), ")")
225
+ src.write("(", "(", visit_node(node.[](:"from")), ")", dots, "(", visit_node(node.[](:"to")), ")", ")")
222
226
  when "LiteralNode"
223
227
  src.write(node.[](:"value"))
224
228
  when "ArrayLiteral"
@@ -237,7 +241,7 @@ EMPTY_ARRAY }
237
241
  str.<<(case c.[](:"type")
238
242
  when "LiteralNode"
239
243
  c.[](:"value")
240
- .[]((1...-1))
244
+ .[](((1)...(-1)))
241
245
  else
242
246
  ["\#{", visit_node(c)
243
247
  .strip, "}"].join
@@ -247,7 +251,11 @@ EMPTY_ARRAY }
247
251
  when "Path"
248
252
  src.write(node.[](:"value"))
249
253
  when "Require"
250
- src.write_ln("require \"#{node.[](:"value")}\"")
254
+ path = node.[](:"value")
255
+ src.write_ln("require \"#{path}\"")
256
+ (if @on_new_file_referenced
257
+ @on_new_file_referenced.call(path, false)
258
+ end)
251
259
  when "Assign", "OpAssign"
252
260
  src.write_ln("#{visit_node(node.[](:"target"))} #{node.[](:"op")}= #{visit_node(node.[](:"value"))
253
261
  .strip}")
@@ -299,11 +307,12 @@ EMPTY_ARRAY }
299
307
  key = case k
300
308
  when String
301
309
  k.to_sym
310
+ .inspect
302
311
  else
303
312
  visit_node(k)
304
313
  end
305
314
  value = visit_node(v)
306
- "#{key.inspect} => #{value}" }
315
+ "#{key} => #{value}" }
307
316
  src.write("{#{contents.join(",\n")}}")
308
317
  (if node.[](:"frozen")
309
318
  src.write(".freeze")
@@ -391,7 +400,7 @@ EMPTY_ARRAY }
391
400
  end
392
401
  # @type var expanded: Array[String]
393
402
  expanded = eval(visit_node(expr))
394
- .map() { |a|
403
+ .map() { |*a|
395
404
  locals = [var_names.join("\", \"")].zip(a)
396
405
  .to_h
397
406
  (if @inside_macro
@@ -435,7 +444,12 @@ EMPTY_ARRAY }
435
444
  src.write("return#{val}")
436
445
  when "TypeDeclaration"
437
446
  src.write_ln("# @type var #{visit_node(node.[](:"var"))}: #{visit_node(node.[](:"declared_type"))}")
438
- src.write_ln("#{visit_node(node.[](:"var"))} = #{visit_node(node.[](:"value"))}")
447
+ value = (if node.[](:"value")
448
+ " = #{visit_node(node.[](:"value"))}"
449
+ else
450
+ nil
451
+ end)
452
+ src.write_ln("#{visit_node(node.[](:"var"))}#{value}")
439
453
  when "ExceptionHandler"
440
454
  src.write_ln("begin")
441
455
  indented(src) { ||
@@ -492,7 +506,7 @@ EMPTY_ARRAY }
492
506
  name = visit_node(node.[](:"name"))
493
507
  src.write_ln("include #{name}")
494
508
  type = RBS::AST::Members::Include.new(name: method(:"TypeName")
495
- .call(name), args: Array.new, annotations: Array.new, location: node.[](:"location"), comment: node.[](:"comment"))
509
+ .call(name), args: Array.new, annotations: Array.new, location: build_location(node), comment: node.[](:"comment"))
496
510
  (if @current_scope
497
511
  @current_scope.members
498
512
  .<<(type)
@@ -510,7 +524,7 @@ EMPTY_ARRAY }
510
524
  name = visit_node(node.[](:"name"))
511
525
  src.write_ln("extend #{name}")
512
526
  type = RBS::AST::Members::Extend.new(name: method(:"TypeName")
513
- .call(name), args: Array.new, annotations: Array.new, location: node.[](:"location"), comment: node.[](:"comment"))
527
+ .call(name), args: Array.new, annotations: Array.new, location: build_location(node), comment: node.[](:"comment"))
514
528
  (if @current_scope
515
529
  @current_scope.members
516
530
  .<<(type)
@@ -538,6 +552,11 @@ EMPTY_ARRAY }
538
552
  .join(" | ")
539
553
  end)
540
554
  src.write(output)
555
+ when "Next"
556
+ (if node.[](:"value")
557
+ val = " #{node.[](:"value")}"
558
+ end)
559
+ src.write("next#{val}")
541
560
  when "EmptyNode"
542
561
  # no op
543
562
  else
@@ -610,7 +629,39 @@ a && a.empty? }
610
629
  end)].reject(&:"empty?")
611
630
  .flatten
612
631
  .join(", ")
613
- "(#{contents})"
632
+ representation = "(#{contents})"
633
+ rp_args = rp.map() { |a|
634
+ RBS::Types::Function::Param.new(name: visit_node(a)
635
+ .to_sym, type: RBS::Types::Bases::Any.new(location: build_location(a)))
636
+ }
637
+ op_args = op.map() { |a|
638
+ RBS::Types::Function::Param.new(name: visit_node(a)
639
+ .to_sym, type: RBS::Types::Bases::Any.new(location: build_location(a)))
640
+ }
641
+ rpa = (if rest_p
642
+ RBS::Types::Function::Param.new(name: rest_p.to_sym, type: RBS::Types::Bases::Any.new(location: build_location(node)))
643
+ else
644
+ nil
645
+ end)
646
+ {:representation => representation,
647
+ :types => {:required_positionals => rp_args,
648
+ :optional_positionals => op_args,
649
+ :rest_positionals => rpa,
650
+ :trailing_positionals => EMPTY_ARRAY,
651
+ :required_keywords => node.[](:"req_kw_args") || EMPTY_HASH,
652
+ :optional_keywords => node.[](:"opt_kw_args") || EMPTY_HASH,
653
+ :rest_keywords => (if node.[](:"rest_kw_args")
654
+ RBS::Types::Function::Param.new(name: visit_node(node.[](:"rest_kw_args"))
655
+ .to_sym, type: RBS::Types::Bases::Any.new(location: build_location(node)))
656
+ else
657
+ nil
658
+ end)
659
+ }.freeze}.freeze
660
+ end
661
+ def build_location(node)
662
+ unless node.[](:"location")
663
+ return nil
664
+ end
614
665
  end
615
666
  end
616
667
  end
data/lib/gloss/watcher.rb CHANGED
@@ -3,36 +3,72 @@
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
- require "listen"
6
+ require "listen"
7
7
  module Gloss
8
8
  class Watcher
9
- def initialize()
10
- @paths = ["src/"]
9
+ def initialize(paths)
10
+ @paths = paths
11
+ (if @paths.empty?
12
+ @paths = [File.join(Dir.pwd, Config.src_dir)]
13
+ @only = /(?:(\.gl|(?:(?<=\/)[^\.\/]+))\z|\A[^\.\/]+\z)/
14
+ else
15
+ file_names = Array.new
16
+ paths = Array.new
17
+ @paths.each() { |pa|
18
+ pn = Pathname.new(pa)
19
+ paths.<<(pn.parent
20
+ .to_s)
21
+ file_names.<<((if pn.file?
22
+ pn.basename
23
+ .to_s
24
+ else
25
+ pa
26
+ end))
27
+ }
28
+ @paths = paths.uniq
29
+ @only = /#{Regexp.union(file_names)}/
30
+ end)
11
31
  end
12
32
  def watch()
13
- puts("=====> Now listening for changes in #{@paths.join(", ")}")
14
- listener = Listen.to(*@paths, latency: 2) { |modified, added, removed|
33
+ Gloss.logger
34
+ .info("Now listening for changes in #{@paths.join(", ")}")
35
+ listener = Listen.to(*@paths, latency: 2, only: @only) { |modified, added, removed|
15
36
  modified.+(added)
16
37
  .each() { |f|
38
+ Gloss.logger
39
+ .info("Rewriting #{f}")
17
40
  content = File.read(f)
18
- Writer.new(Builder.new(content)
41
+ err = catch(:"error") { ||
42
+ Writer.new(Visitor.new(Parser.new(content)
43
+ .run)
19
44
  .run, f)
20
45
  .run
46
+ nil }
47
+ (if err
48
+ Gloss.logger
49
+ .error(err)
50
+ else
51
+ Gloss.logger
52
+ .info("Done")
53
+ end)
21
54
  }
22
55
  removed.each() { |f|
23
56
  out_path = Utils.src_path_to_output_path(f)
57
+ Gloss.logger
58
+ .info("Removing #{out_path}")
24
59
  (if File.exist?(out_path)
25
60
  File.delete(out_path)
26
61
  end)
62
+ Gloss.logger
63
+ .info("Done")
27
64
  }
28
65
  }
29
- listener.start
30
66
  begin
31
- loop() { ||
32
- sleep(10)
33
- }
67
+ listener.start
68
+ sleep
34
69
  rescue Interrupt
35
- puts("=====> Interrupt signal received, shutting down")
70
+ Gloss.logger
71
+ .info("Interrupt signal received, shutting down")
36
72
  exit(0)
37
73
  end
38
74
  end
data/lib/gloss/writer.rb CHANGED
@@ -3,20 +3,13 @@
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
- require "pathname"
6
+ require "pathname"
7
7
  require "fileutils"
8
8
  module Gloss
9
- module Utils
10
- module_function
11
- def src_path_to_output_path(src_path)
12
- src_path.sub(/\A(?:\.\/)?#{Config.src_dir}\/?/, "")
13
- .sub(/\.gl$/, ".rb")
14
- end
15
- end
16
9
  class Writer
17
- include Utils
18
- def initialize(content, src_path, output_path = Pathname.new(src_path_to_output_path(src_path)))
10
+ def initialize(content, src_path, output_path = Pathname.new(Utils.src_path_to_output_path(src_path)))
19
11
  @content = content
12
+ @src_path = src_path
20
13
  @output_path = output_path
21
14
  end
22
15
  def run()
@@ -25,8 +18,26 @@ module Gloss
25
18
  FileUtils.mkdir_p(@output_path.parent)
26
19
  end
27
20
  File.open(@output_path, "wb") { |file|
28
- file.<<(@content)
21
+ sb = shebang
22
+ (if sb
23
+ file.puts(sb)
24
+ end)
25
+ file.puts(@content)
29
26
  }
30
27
  end
28
+ private def shebang()
29
+ (if @output_path.executable?
30
+ first_line = File.open(@src_path) { |f|
31
+ f.readline
32
+ }
33
+ (if first_line.start_with?("#!")
34
+ first_line
35
+ else
36
+ nil
37
+ end)
38
+ else
39
+ nil
40
+ end)
41
+ end
31
42
  end
32
43
  end