gloss 0.0.4 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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