unparser 0.5.6 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -114,9 +114,9 @@ module Unparser
114
114
  # @api private
115
115
  #
116
116
  def capture_content
117
- size_before = @content.size
117
+ size_before = content.size
118
118
  yield
119
- @content[size_before..-1]
119
+ content[size_before..]
120
120
  end
121
121
 
122
122
  # Write raw fragment to buffer
data/lib/unparser/cli.rb CHANGED
@@ -76,6 +76,7 @@ module Unparser
76
76
  @targets = []
77
77
 
78
78
  @fail_fast = false
79
+ @start_with = nil
79
80
  @success = true
80
81
  @validation = :validation
81
82
  @verbose = false
@@ -3,7 +3,7 @@
3
3
  module Unparser
4
4
  # Class to colorize strings
5
5
  class Color
6
- include Adamantium::Flat, Concord.new(:code)
6
+ include Adamantium, Concord.new(:code)
7
7
 
8
8
  # Format text with color
9
9
  #
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unparser
4
+ # A mixin to define a composition
5
+ #
6
+ # Original code before vendoring and reduction from: https://github.com/mbj/concord.
7
+ class Concord < Module
8
+ include Adamantium, Equalizer.new(:names)
9
+
10
+ # The maximum number of objects the hosting class is composed of
11
+ MAX_NR_OF_OBJECTS = 3
12
+
13
+ # Return names
14
+ #
15
+ # @return [Enumerable<Symbol>]
16
+ #
17
+ # @api private
18
+ #
19
+ attr_reader :names
20
+
21
+ private
22
+
23
+ # Initialize object
24
+ #
25
+ # @return [undefined]
26
+ #
27
+ # @api private
28
+ #
29
+ # rubocop:disable Lint/MissingSuper
30
+ def initialize(*names)
31
+ if names.length > MAX_NR_OF_OBJECTS
32
+ fail "Composition of more than #{MAX_NR_OF_OBJECTS} objects is not allowed"
33
+ end
34
+
35
+ @names = names
36
+ define_initialize
37
+ define_readers
38
+ define_equalizer
39
+ end
40
+ # rubocop:enable Lint/MissingSuper
41
+
42
+ # Define equalizer
43
+ #
44
+ # @return [undefined]
45
+ #
46
+ # @api private
47
+ #
48
+ def define_equalizer
49
+ include(Equalizer.new(*names))
50
+ end
51
+
52
+ # Define readers
53
+ #
54
+ # @return [undefined]
55
+ #
56
+ # @api private
57
+ #
58
+ def define_readers
59
+ attribute_names = names
60
+ attr_reader(*attribute_names)
61
+
62
+ protected(*attribute_names) if attribute_names.any?
63
+ end
64
+
65
+ # Define initialize method
66
+ #
67
+ # @return [undefined]
68
+ #
69
+ # @api private
70
+ #
71
+ #
72
+ def define_initialize
73
+ ivars = instance_variable_names
74
+ size = names.size
75
+
76
+ define_method :initialize do |*args|
77
+ args_size = args.size
78
+ unless args_size.equal?(size)
79
+ fail ArgumentError, "wrong number of arguments (#{args_size} for #{size})"
80
+ end
81
+
82
+ ivars.zip(args) { |ivar, arg| instance_variable_set(ivar, arg) }
83
+ end
84
+ end
85
+
86
+ # Return instance variable names
87
+ #
88
+ # @return [String]
89
+ #
90
+ # @api private
91
+ #
92
+ def instance_variable_names
93
+ names.map { |name| "@#{name}" }
94
+ end
95
+
96
+ # Mixin for public attribute readers
97
+ class Public < self
98
+
99
+ # Hook called when module is included
100
+ #
101
+ # @param [Class,Module] descendant
102
+ #
103
+ # @return [undefined]
104
+ #
105
+ # @api private
106
+ #
107
+ def included(descendant)
108
+ names.each do |name|
109
+ descendant.__send__(:public, name)
110
+ end
111
+ end
112
+ end # Public
113
+ end # Concord
114
+ end # Unparser
data/lib/unparser/diff.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  module Unparser
4
4
  # Class to create diffs from source code
5
5
  class Diff
6
- include Adamantium::Flat, Concord.new(:old, :new)
6
+ include Adamantium, Concord.new(:old, :new)
7
7
 
8
8
  ADDITION = '+'
9
9
  DELETION = '-'
@@ -0,0 +1,153 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unparser
4
+ module RequireBlock
5
+
6
+ private
7
+
8
+ # Raise error unless block is provided
9
+ #
10
+ # @raise [MissingBlockError]
11
+ # if no block is given
12
+ #
13
+ # @return [self]
14
+ def require_block
15
+ fail LocalJumpError unless block_given?
16
+
17
+ self
18
+ end
19
+ end # RequireBLock
20
+
21
+ class Either
22
+ include(
23
+ Adamantium,
24
+ Concord.new(:value),
25
+ RequireBlock
26
+ )
27
+
28
+ # Execute block and wrap error in left
29
+ #
30
+ # @param [Class<Exception>] exception
31
+ #
32
+ # @return [Either<Exception, Object>]
33
+ def self.wrap_error(*exceptions)
34
+ Right.new(yield)
35
+ rescue *exceptions => error
36
+ Left.new(error)
37
+ end
38
+
39
+ # Test for left constructor
40
+ #
41
+ # @return [Boolean]
42
+ def left?
43
+ instance_of?(Left)
44
+ end
45
+
46
+ # Test for right constructor
47
+ #
48
+ # @return [Boolean]
49
+ def right?
50
+ instance_of?(Right)
51
+ end
52
+
53
+ class Left < self
54
+ # Evaluate functor block
55
+ #
56
+ # @return [Either::Left<Object>]
57
+ def fmap(&block)
58
+ require_block(&block)
59
+ end
60
+
61
+ # Evaluate applicative block
62
+ #
63
+ # @return [Either::Left<Object>]
64
+ def bind(&block)
65
+ require_block(&block)
66
+ end
67
+
68
+ # Unwrap value from left
69
+ #
70
+ # @return [Object]
71
+ def from_left
72
+ value
73
+ end
74
+
75
+ # Unwrap value from right
76
+ #
77
+ # @return [Object]
78
+ #
79
+ def from_right
80
+ if block_given?
81
+ yield(value)
82
+ else
83
+ fail "Expected right value, got #{inspect}"
84
+ end
85
+ end
86
+
87
+ # Map over left value
88
+ #
89
+ # @return [Either::Right<Object>]
90
+ def lmap
91
+ Left.new(yield(value))
92
+ end
93
+
94
+ # Evaluate left side of branch
95
+ #
96
+ # @param [#call] left
97
+ # @param [#call] _right
98
+ def either(left, _right)
99
+ left.call(value)
100
+ end
101
+ end # Left
102
+
103
+ class Right < self
104
+ # Evaluate functor block
105
+ #
106
+ # @return [Either::Right<Object>]
107
+ def fmap
108
+ Right.new(yield(value))
109
+ end
110
+
111
+ # Evaluate applicative block
112
+ #
113
+ # @return [Either<Object>]
114
+ def bind
115
+ yield(value)
116
+ end
117
+
118
+ # Unwrap value from left
119
+ #
120
+ # @return [Object]
121
+ #
122
+ def from_left
123
+ if block_given?
124
+ yield(value)
125
+ else
126
+ fail "Expected left value, got #{inspect}"
127
+ end
128
+ end
129
+
130
+ # Unwrap value from right
131
+ #
132
+ # @return [Object]
133
+ def from_right
134
+ value
135
+ end
136
+
137
+ # Map over left value
138
+ #
139
+ # @return [Either::Right<Object>]
140
+ def lmap(&block)
141
+ require_block(&block)
142
+ end
143
+
144
+ # Evaluate right side of branch
145
+ #
146
+ # @param [#call] _left
147
+ # @param [#call] right
148
+ def either(_left, right)
149
+ right.call(value)
150
+ end
151
+ end # Right
152
+ end # Either
153
+ end # Unparser
@@ -14,6 +14,12 @@ module Unparser
14
14
 
15
15
  handle(*MAP.keys)
16
16
 
17
+ def emit_heredoc_reminders
18
+ children.each do |node|
19
+ emitter(node).emit_heredoc_reminders
20
+ end
21
+ end
22
+
17
23
  private
18
24
 
19
25
  def dispatch
@@ -60,7 +60,7 @@ module Unparser
60
60
  end
61
61
 
62
62
  def write_symbol_body(symbol)
63
- write(symbol.inspect[1..-1])
63
+ write(symbol.inspect[1..])
64
64
  end
65
65
  end # Pin
66
66
  end # Emitter
@@ -36,7 +36,7 @@ module Unparser
36
36
  handle :indexasgn
37
37
 
38
38
  VALUE_RANGE = (1..-2).freeze
39
- NO_VALUE_PARENT = IceNine.deep_freeze(%i[and_asgn op_asgn or_asgn].to_set)
39
+ NO_VALUE_PARENT = %i[and_asgn op_asgn or_asgn].to_set.freeze
40
40
 
41
41
  private_constant(*constants(false))
42
42
 
@@ -7,10 +7,10 @@ module Unparser
7
7
  class BinaryAssign < self
8
8
  children :target, :expression
9
9
 
10
- MAP = IceNine.deep_freeze(
10
+ MAP = {
11
11
  and_asgn: '&&=',
12
12
  or_asgn: '||='
13
- )
13
+ }.freeze
14
14
 
15
15
  handle(*MAP.keys)
16
16
 
@@ -28,11 +28,11 @@ module Unparser
28
28
  RATIONAL_FORMAT = 'i'.freeze
29
29
 
30
30
  MAP =
31
- IceNine.deep_freeze(
31
+ {
32
32
  ::Float => :float,
33
33
  ::Rational => :rational,
34
34
  ::Integer => :int
35
- )
35
+ }.freeze
36
36
 
37
37
  private
38
38
 
@@ -4,7 +4,7 @@ module Unparser
4
4
  class Emitter
5
5
  # Emitter for simple nodes that generate a single token
6
6
  class Simple < self
7
- MAP = IceNine.deep_freeze(
7
+ MAP = {
8
8
  __ENCODING__: '__ENCODING__',
9
9
  __FILE__: '__FILE__',
10
10
  __LINE__: '__LINE__',
@@ -19,7 +19,7 @@ module Unparser
19
19
  self: 'self',
20
20
  true: 'true',
21
21
  zsuper: 'super'
22
- )
22
+ }.freeze
23
23
 
24
24
  handle(*MAP.keys)
25
25
 
@@ -5,7 +5,7 @@ module Unparser
5
5
 
6
6
  # Emitter base class
7
7
  class Emitter
8
- include Adamantium::Flat, AbstractType, Constants, Generation, NodeHelpers
8
+ include Adamantium, AbstractType, Constants, Generation, NodeHelpers
9
9
  include Anima.new(:buffer, :comments, :node, :local_variable_scope)
10
10
 
11
11
  public :node
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unparser
4
+ # Define equality, equivalence and inspection methods
5
+ #
6
+ # Original code before vendoring and reduction from: https://github.com/dkubb/equalizer.
7
+ class Equalizer < Module
8
+ # Initialize an Equalizer with the given keys
9
+ #
10
+ # Will use the keys with which it is initialized to define #cmp?,
11
+ # #hash, and #inspect
12
+ #
13
+ # @param [Array<Symbol>] keys
14
+ #
15
+ # @return [undefined]
16
+ #
17
+ # @api private
18
+ #
19
+ # rubocop:disable Lint/MissingSuper
20
+ def initialize(*keys)
21
+ @keys = keys
22
+ define_methods
23
+ freeze
24
+ end
25
+ # rubocop:enable Lint/MissingSuper
26
+
27
+ private
28
+
29
+ def included(descendant)
30
+ descendant.include(Methods)
31
+ end
32
+
33
+ def define_methods
34
+ define_cmp_method
35
+ define_hash_method
36
+ define_inspect_method
37
+ end
38
+
39
+ def define_cmp_method
40
+ keys = @keys
41
+ define_method(:cmp?) do |comparator, other|
42
+ keys.all? do |key|
43
+ __send__(key).public_send(comparator, other.__send__(key))
44
+ end
45
+ end
46
+ private :cmp?
47
+ end
48
+
49
+ def define_hash_method
50
+ keys = @keys
51
+ define_method(:hash) do
52
+ keys.map(&public_method(:__send__)).push(self.class).hash
53
+ end
54
+ end
55
+
56
+ def define_inspect_method
57
+ keys = @keys
58
+ define_method(:inspect) do
59
+ klass = self.class
60
+ name = klass.name || klass.inspect
61
+ "#<#{name}#{keys.map { |key| " #{key}=#{__send__(key).inspect}" }.join}>"
62
+ end
63
+ end
64
+
65
+ # The comparison methods
66
+ module Methods
67
+ # Compare the object with other object for equality
68
+ #
69
+ # @example
70
+ # object.eql?(other) # => true or false
71
+ #
72
+ # @param [Object] other
73
+ # the other object to compare with
74
+ #
75
+ # @return [Boolean]
76
+ #
77
+ # @api public
78
+ def eql?(other)
79
+ instance_of?(other.class) && cmp?(__method__, other)
80
+ end
81
+
82
+ # Compare the object with other object for equivalency
83
+ #
84
+ # @example
85
+ # object == other # => true or false
86
+ #
87
+ # @param [Object] other
88
+ # the other object to compare with
89
+ #
90
+ # @return [Boolean]
91
+ #
92
+ # @api public
93
+ def ==(other)
94
+ instance_of?(other.class) && cmp?(__method__, other)
95
+ end
96
+ end # module Methods
97
+ end # class Equalizer
98
+ end # Unparser
@@ -19,7 +19,10 @@ module Unparser
19
19
  end
20
20
 
21
21
  def binary_syntax_allowed?
22
- selector_binary_operator? && arguments.one? && !n_splat?(arguments.first)
22
+ selector_binary_operator? \
23
+ && arguments.one? \
24
+ && !n_splat?(arguments.first) \
25
+ && !n_kwargs?(arguments.first)
23
26
  end
24
27
 
25
28
  def selector_unary_operator?
@@ -48,7 +51,7 @@ module Unparser
48
51
  memoize :assignment?
49
52
 
50
53
  def arguments
51
- children[2..-1]
54
+ children[2..]
52
55
  end
53
56
  memoize :arguments
54
57
 
@@ -6,7 +6,7 @@ module Unparser
6
6
 
7
7
  def self.included(descendant)
8
8
  descendant.class_eval do
9
- include Adamantium::Flat, Concord.new(:node)
9
+ include Adamantium, Concord.new(:node)
10
10
 
11
11
  extend DSL
12
12
  end
@@ -36,18 +36,20 @@ module Unparser
36
36
  args
37
37
  array
38
38
  array_pattern
39
- empty_else
40
39
  begin
41
40
  block
42
41
  cbase
43
42
  const
44
43
  dstr
44
+ empty_else
45
45
  ensure
46
46
  hash
47
47
  hash_pattern
48
48
  if
49
49
  in_pattern
50
50
  int
51
+ kwarg
52
+ kwargs
51
53
  kwsplat
52
54
  lambda
53
55
  match_rest
@@ -3,7 +3,7 @@
3
3
  module Unparser
4
4
  # Validation of unparser results
5
5
  class Validation
6
- include Adamantium::Flat, Anima.new(
6
+ include Adamantium, Anima.new(
7
7
  :generated_node,
8
8
  :generated_source,
9
9
  :identification,
@@ -64,7 +64,7 @@ module Unparser
64
64
 
65
65
  new(
66
66
  identification: '(string)',
67
- original_source: MPrelude::Either::Right.new(original_source),
67
+ original_source: Either::Right.new(original_source),
68
68
  original_node: original_node,
69
69
  generated_source: generated_source,
70
70
  generated_node: generated_node
@@ -86,7 +86,7 @@ module Unparser
86
86
  new(
87
87
  identification: '(string)',
88
88
  original_source: generated_source,
89
- original_node: MPrelude::Either::Right.new(original_node),
89
+ original_node: Either::Right.new(original_node),
90
90
  generated_source: generated_source,
91
91
  generated_node: generated_node
92
92
  )
@@ -3,7 +3,7 @@
3
3
  module Unparser
4
4
  module Writer
5
5
  class Binary
6
- include Writer, Adamantium::Flat
6
+ include Writer, Adamantium
7
7
 
8
8
  children :left, :right
9
9
 
@@ -3,22 +3,20 @@
3
3
  module Unparser
4
4
  module Writer
5
5
  class DynamicString
6
- include Writer, Adamantium::Flat
6
+ include Writer, Adamantium
7
7
 
8
- PATTERNS_2 = IceNine.deep_freeze(
8
+ PATTERNS_2 =
9
9
  [
10
- %i[str_empty begin],
11
- %i[begin str_nl]
12
- ]
13
- )
10
+ %i[str_empty begin].freeze,
11
+ %i[begin str_nl].freeze
12
+ ].freeze
14
13
 
15
- PATTERNS_3 = IceNine.deep_freeze(
14
+ PATTERNS_3 =
16
15
  [
17
- %i[begin str_nl_eol str_nl_eol],
18
- %i[str_nl_eol begin str_nl_eol],
19
- %i[str_ws begin str_nl_eol]
20
- ]
21
- )
16
+ %i[begin str_nl_eol str_nl_eol].freeze,
17
+ %i[str_nl_eol begin str_nl_eol].freeze,
18
+ %i[str_ws begin str_nl_eol].freeze
19
+ ].freeze
22
20
 
23
21
  FLAT_INTERPOLATION = %i[ivar cvar gvar nth_ref].to_set.freeze
24
22
 
@@ -3,7 +3,7 @@
3
3
  module Unparser
4
4
  module Writer
5
5
  class Rescue
6
- include Writer, Adamantium::Flat
6
+ include Writer, Adamantium
7
7
 
8
8
  children :body, :rescue_body
9
9
 
@@ -17,7 +17,7 @@ module Unparser
17
17
 
18
18
  write(MAP.fetch(name, name).to_s)
19
19
 
20
- if n_int?(receiver) && selector.equal?(:'+@')
20
+ if n_int?(receiver) && selector.equal?(:+@)
21
21
  write('+')
22
22
  end
23
23
 
@@ -4,10 +4,10 @@ module Unparser
4
4
  module Writer
5
5
  # Writer for send
6
6
  class Send
7
- include Writer, Adamantium::Flat, Constants, Generation
7
+ include Writer, Adamantium, Constants, Generation
8
8
 
9
- INDEX_ASSIGN = :'[]='
10
- INDEX_REFERENCE = :'[]'
9
+ INDEX_ASSIGN = :[]=
10
+ INDEX_REFERENCE = :[]
11
11
 
12
12
  OPERATORS = {
13
13
  csend: '&.',
@@ -45,7 +45,7 @@ module Unparser
45
45
  def effective_writer_class
46
46
  if details.binary_syntax_allowed?
47
47
  Binary
48
- elsif details.selector_unary_operator? && n_send?(node)
48
+ elsif details.selector_unary_operator? && n_send?(node) && arguments.empty?
49
49
  Unary
50
50
  elsif write_as_attribute_assignment?
51
51
  AttributeAssignment
@@ -91,7 +91,11 @@ module Unparser
91
91
  end
92
92
 
93
93
  def parses_as_constant?
94
- n_const?(Unparser.parse(selector.to_s))
94
+ test = Unparser.parse_either(selector.to_s).from_right do
95
+ fail InvalidNodeError.new("Invalid selector for send node: #{selector.inspect}", node)
96
+ end
97
+
98
+ n_const?(test)
95
99
  end
96
100
 
97
101
  def details