unparser 0.8.2 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c9a2bc4c065381b615f71cb36770c6edc2633ce160540426d28ebb6ccda689d8
4
- data.tar.gz: c0952ffb8269388f5de64ea68719d785a59dd7f9869907c69df623aeb10d9006
3
+ metadata.gz: 55ff925fe35a0edc1d97f78f4c2cf18590a3f2b4a11bc33e4b786a5954b4a38b
4
+ data.tar.gz: 41298c66c043f4f886215b23f6e1b16cd5bfc4fda9cac590a4dcfbf79c7b3ad8
5
5
  SHA512:
6
- metadata.gz: f0151e34f94305994a4e6fac9ea360fb5918b114e3e1f2ab9e1a6a6b5359134baa972d27a5c09410406185a1c91b5424590eb33ce1d343e928a4eb09bdbfa4e3
7
- data.tar.gz: 0fe83efcc1cc934e3d045530c06f1addac19bf30bc101740bf56d8c4129ef2c5c7989498797d5098858b946094ec8962aecf55fa42bba866774ef34fc323fcf7
6
+ metadata.gz: '08b368b24f292f467d75f2cbbea4488dc117fbfc1619c0ab14eee351121221bf63d0c60aa8cffb1cc9f795eb87fd0a5e0d1cefd196ec955f8d3c0b12784f57a6'
7
+ data.tar.gz: 9a21fffcd287e446c6e5a459556d1c863490ebbaa906ea4f775619286405d18fab3821c5fc3e14ba4ab8fc8f68de344b6a71565f7e8980f8eac43a762b7caf66
data/README.md CHANGED
@@ -10,7 +10,7 @@ The following constraints apply:
10
10
 
11
11
  * No support for macruby extensions
12
12
  * Only support for the [modern AST](https://github.com/whitequark/parser/#usage) format
13
- * Only support for Ruby >= 3.2
13
+ * Only support for Ruby >= 3.3
14
14
 
15
15
  Notable Users:
16
16
 
@@ -173,12 +173,12 @@ Included Libraries
173
173
 
174
174
  For dependency reduction reasons unparser ships vendored (and reduced) versions of:
175
175
 
176
- * [abstract_type](https://github.com/mbj/concord) -> Unparser::AbstractType
176
+ * [abstract_type](https://github.com/dkubb/abstract_type) -> Unparser::AbstractType
177
177
  * [adamantium](https://github.com/dkubb/adamantium) -> Unparser::Adamantium
178
- * [anima](https://github.com/mbj/concord) -> Unparser::Anima
179
- * [concord](https://github.com/mbj/concord) -> Unparser::Concord
180
- * [memoizable](https://github.com/dkubb/memoizable) -> Unparser::Adamantium
181
- * [mprelude](https://github.com/dkubb/memoizable) -> Unparser::Either
178
+ * [anima](https://github.com/mbj/anima) -> Unparser::Anima
179
+ * [equalizer](https://github.com/dkubb/equalizer) -> Unparser::Equalizer
180
+ * [memoizable](https://github.com/dkubb/memoizable) -> Unparser::Memoizable
181
+ * [mprelude](http://prelude.rubyforge.org/) -> Unparser::Either
182
182
 
183
183
  Contributing
184
184
  -------------
@@ -50,9 +50,7 @@ module Unparser
50
50
  #
51
51
  # @return [Hash]
52
52
  def attributes_hash(object)
53
- attributes.each_with_object({}) do |attribute, attributes_hash|
54
- attributes_hash[attribute.name] = attribute.get(object)
55
- end
53
+ attributes.to_h { |attribute| [attribute.name, attribute.get(object)] }
56
54
  end
57
55
 
58
56
  # Return attribute names
data/lib/unparser/ast.rb CHANGED
@@ -90,7 +90,14 @@ module Unparser
90
90
 
91
91
  # AST enumerator
92
92
  class Enumerator
93
- include Adamantium, Concord.new(:node, :controller), Enumerable
93
+ include Adamantium, Equalizer.new(:node, :controller), Enumerable
94
+
95
+ attr_reader :node, :controller
96
+
97
+ def initialize(node, controller)
98
+ @node = node
99
+ @controller = controller
100
+ end
94
101
 
95
102
  # Return each node
96
103
  #
@@ -130,38 +137,18 @@ module Unparser
130
137
  select { |node| node.type.equal?(type) }
131
138
  end
132
139
 
133
- # Return frozne set of objects
134
- #
135
- # @param [Enumerable] enumerable
136
- #
137
- # @return [Set]
138
- #
139
- # @api private
140
- #
141
- def self.set(enumerable)
142
- enumerable.to_set.freeze
143
- end
144
- private_class_method :set
145
-
146
- # Return nodes of type
147
- #
148
- # @param [Parser::AST::Node] node
149
- # @param [Symbol] type
150
- #
151
- # @return [Enumerable<Parser::AST::Node]
152
- #
153
- # @api private
154
- #
155
- def self.type(node, type)
156
- new(node).type(type)
157
- end
158
- private_class_method :type
159
-
160
140
  end # Enumerator
161
141
 
162
142
  # Controlled AST walker walking the AST in deeth first search with pre order
163
143
  class Walker
164
- include Concord.new(:block, :controller)
144
+ include Equalizer.new(:block, :controller)
145
+
146
+ attr_reader :block, :controller
147
+
148
+ def initialize(block, controller)
149
+ @block = block
150
+ @controller = controller
151
+ end
165
152
 
166
153
  # Call ast walker
167
154
  #
data/lib/unparser/cli.rb CHANGED
@@ -14,7 +14,15 @@ module Unparser
14
14
 
15
15
  # Path target
16
16
  class Path < self
17
- include Concord.new(:path)
17
+ include Equalizer.new(:path)
18
+
19
+ attr_reader :path
20
+
21
+ # rubocop:disable Lint/MissingSuper
22
+ def initialize(path)
23
+ @path = path
24
+ end
25
+ # rubocop:enable Lint/MissingSuper
18
26
 
19
27
  # Validation for this target
20
28
  #
@@ -33,7 +41,13 @@ module Unparser
33
41
 
34
42
  # String target
35
43
  class String
36
- include Concord.new(:string)
44
+ include Equalizer.new(:string)
45
+
46
+ attr_reader :string
47
+
48
+ def initialize(string)
49
+ @string = string
50
+ end
37
51
 
38
52
  # Validation for this target
39
53
  #
@@ -3,7 +3,13 @@
3
3
  module Unparser
4
4
  # Class to colorize strings
5
5
  class Color
6
- include Adamantium, Concord.new(:code)
6
+ include Adamantium, Equalizer.new(:code)
7
+
8
+ attr_reader :code
9
+
10
+ def initialize(code)
11
+ @code = code
12
+ end
7
13
 
8
14
  # Format text with color
9
15
  #
data/lib/unparser/diff.rb CHANGED
@@ -3,7 +3,14 @@
3
3
  module Unparser
4
4
  # Class to create diffs from source code
5
5
  class Diff
6
- include Adamantium, Concord.new(:old, :new)
6
+ include Adamantium, Equalizer.new(:old, :new)
7
+
8
+ attr_reader :old, :new
9
+
10
+ def initialize(old, new)
11
+ @old = old
12
+ @new = new
13
+ end
7
14
 
8
15
  ADDITION = '+'
9
16
  DELETION = '-'
@@ -19,11 +19,13 @@ module Unparser
19
19
  end # RequireBLock
20
20
 
21
21
  class Either
22
- include(
23
- Adamantium,
24
- Concord.new(:value),
25
- RequireBlock
26
- )
22
+ include Adamantium, Equalizer.new(:value), RequireBlock
23
+
24
+ attr_reader :value
25
+
26
+ def initialize(value)
27
+ @value = value
28
+ end
27
29
 
28
30
  # Execute block and wrap error in left
29
31
  #
@@ -13,23 +13,8 @@ module Unparser
13
13
 
14
14
  private
15
15
 
16
- # mutant:disable
17
16
  def dispatch
18
- if inspect_breaks_parsing?
19
- write(":#{value.name.inspect}")
20
- else
21
- write(value.inspect)
22
- end
23
- end
24
-
25
- # mutant:disable
26
- def inspect_breaks_parsing?
27
- return false unless RUBY_VERSION < '3.2.'
28
-
29
- Unparser.parse(value.inspect)
30
- false
31
- rescue Parser::SyntaxError
32
- true
17
+ write(value.inspect)
33
18
  end
34
19
  end # Symbol
35
20
 
@@ -4,95 +4,129 @@ module Unparser
4
4
  # Define equality, equivalence and inspection methods
5
5
  #
6
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
7
+ module Equalizer
8
+ # Creates a module providing equality methods based on the given attributes
9
9
  #
10
- # Will use the keys with which it is initialized to define #cmp?,
11
- # #hash, and #inspect
10
+ # @param keys [Array<Symbol>] attribute names to use for equality
11
+ # @param inspect [Boolean] whether to override #inspect and #pretty_print
12
+ # @return [Module] a module to include in your class
13
+ # @raise [ArgumentError] if keys is empty or contains non-Symbols
12
14
  #
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
15
+ # @api public
16
+ def self.new(*keys, inspect: true)
17
+ build_module(keys.freeze, inspect:)
37
18
  end
38
19
 
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
20
+ # Instance methods mixed into classes that include an Equalizer module
21
+ #
22
+ # @api private
23
+ module InstanceMethods
24
+ # Equality comparison allowing subclasses
25
+ #
26
+ # @param other [Object] object to compare
27
+ # @return [Boolean] true if other is_a? same class with equal attributes
28
+ def ==(other)
29
+ other.is_a?(self.class) &&
30
+ cmp?(:==, other)
45
31
  end
46
- private :cmp?
47
- end
48
32
 
49
- def define_hash_method
50
- keys = @keys
51
- define_method(:hash) do
52
- keys.map(&public_method(:__send__)).push(self.class).hash
33
+ # Strict equality requiring exact class match
34
+ #
35
+ # @param other [Object] object to compare
36
+ # @return [Boolean] true if other is exact same class with eql? attributes
37
+ def eql?(other)
38
+ other.instance_of?(self.class) &&
39
+ cmp?(:eql?, other)
53
40
  end
54
- end
55
41
 
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}>"
42
+ # Hash code based on class and attribute values
43
+ #
44
+ # @return [Integer] hash code
45
+ def hash
46
+ [self.class, *deconstruct].hash
62
47
  end
63
- end
64
48
 
65
- # The comparison methods
66
- module Methods
67
- # Compare the object with other object for equality
49
+ # Array deconstruction for pattern matching
68
50
  #
69
- # @example
70
- # object.eql?(other) # => true or false
51
+ # @return [Array] attribute values in order
52
+ def deconstruct
53
+ equalizer_keys.map { |key| public_send(key) }
54
+ end
55
+
56
+ # Hash deconstruction for pattern matching
71
57
  #
72
- # @param [Object] other
73
- # the other object to compare with
58
+ # @param requested [Array<Symbol>, nil] keys to include, or nil for all
59
+ # @return [Hash{Symbol => Object}] requested attribute key-value pairs
60
+ def deconstruct_keys(requested)
61
+ subset = requested.nil? ? equalizer_keys : equalizer_keys & requested
62
+ subset.to_h { |key| [key, public_send(key)] }
63
+ end
64
+
65
+ private
66
+
67
+ # Compare all attributes using the given comparator
74
68
  #
75
- # @return [Boolean]
69
+ # @param comparator [Symbol] method to use for comparison
70
+ # @param other [Object] object to compare against
71
+ # @return [Boolean] true if all attributes match
76
72
  #
77
- # @api public
78
- def eql?(other)
79
- instance_of?(other.class) && cmp?(__method__, other)
73
+ # @api private
74
+ def cmp?(comparator, other)
75
+ equalizer_keys.all? do |key|
76
+ public_send(key)
77
+ .public_send(comparator, other.public_send(key))
78
+ end
80
79
  end
80
+ end
81
81
 
82
- # Compare the object with other object for equivalency
83
- #
84
- # @example
85
- # object == other # => true or false
82
+ # Instance methods for inspect and pretty print output
83
+ #
84
+ # @api private
85
+ module InspectMethods
86
+ # String representation showing only equalizer attributes
86
87
  #
87
- # @param [Object] other
88
- # the other object to compare with
88
+ # @return [String] inspect output
89
+ def inspect
90
+ attrs = equalizer_keys
91
+ .map { |key| "@#{key}=#{public_send(key).inspect}" }
92
+ .join(', ')
93
+ Object.instance_method(:to_s).bind_call(self).sub(/>\z/, " #{attrs}>")
94
+ end
95
+
96
+ # Pretty print output using PP's object formatting
89
97
  #
90
- # @return [Boolean]
98
+ # @param q [PP] pretty printer
99
+ # @return [void]
100
+ def pretty_print(pretty_printer)
101
+ pretty_printer.pp_object(self)
102
+ end
103
+
104
+ # Instance variables to display in pretty print output
91
105
  #
92
- # @api public
93
- def ==(other)
94
- instance_of?(other.class) && cmp?(__method__, other)
106
+ # @return [Array<Symbol>] instance variable names
107
+ def pretty_print_instance_variables
108
+ equalizer_keys.map { |key| :"@#{key}" }
95
109
  end
96
- end # module Methods
97
- end # class Equalizer
110
+ end
111
+
112
+ # Builds the module with equality methods for the given keys
113
+ #
114
+ # @param keys [Array<Symbol>] attribute names (frozen)
115
+ # @param inspect [Boolean] whether to include inspect methods
116
+ # @return [Module] the configured module
117
+ #
118
+ # @api private
119
+ def self.build_module(keys, inspect:)
120
+ Module.new do
121
+ include InstanceMethods
122
+ include InspectMethods if inspect
123
+
124
+ set_temporary_name("Equalizer(#{keys.join(', ')})")
125
+
126
+ define_method(:equalizer_keys) { keys }
127
+ private :equalizer_keys
128
+ end
129
+ end
130
+ private_class_method :build_module
131
+ end # module Equalizer
98
132
  end # Unparser
@@ -7,7 +7,13 @@ module Unparser
7
7
  # mutant:disable
8
8
  def self.included(descendant)
9
9
  descendant.class_eval do
10
- include Adamantium, Concord.new(:node)
10
+ include Adamantium, Equalizer.new(:node)
11
+
12
+ attr_reader :node
13
+
14
+ def initialize(node)
15
+ @node = node
16
+ end
11
17
 
12
18
  extend DSL
13
19
  end
data/lib/unparser.rb CHANGED
@@ -9,7 +9,6 @@ require 'unparser/adamantium'
9
9
  require 'unparser/adamantium/method_builder'
10
10
  require 'unparser/abstract_type'
11
11
 
12
- require 'unparser/concord'
13
12
  require 'unparser/either'
14
13
  require 'unparser/anima'
15
14
  require 'unparser/anima/attribute'
@@ -73,7 +72,7 @@ module Unparser # rubocop:disable Metrics/ModuleLength
73
72
  EMPTY_STRING = ''.freeze
74
73
  EMPTY_ARRAY = [].freeze
75
74
 
76
- private_constant(*constants(false) - %i[Adamantium AbstractType Anima Concord Either Equalizer Memoizable])
75
+ private_constant(*constants(false) - %i[Adamantium AbstractType Anima Either Equalizer Memoizable])
77
76
 
78
77
  # Error raised when unparser encounters an invalid AST
79
78
  class InvalidNodeError < RuntimeError
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unparser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.2
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Markus Schirp
@@ -75,28 +75,28 @@ dependencies:
75
75
  name: mutant
76
76
  requirement: !ruby/object:Gem::Requirement
77
77
  requirements:
78
- - - "~>"
78
+ - - ">="
79
79
  - !ruby/object:Gem::Version
80
80
  version: 0.14.2
81
81
  type: :development
82
82
  prerelease: false
83
83
  version_requirements: !ruby/object:Gem::Requirement
84
84
  requirements:
85
- - - "~>"
85
+ - - ">="
86
86
  - !ruby/object:Gem::Version
87
87
  version: 0.14.2
88
88
  - !ruby/object:Gem::Dependency
89
89
  name: mutant-rspec
90
90
  requirement: !ruby/object:Gem::Requirement
91
91
  requirements:
92
- - - "~>"
92
+ - - ">="
93
93
  - !ruby/object:Gem::Version
94
94
  version: 0.14.2
95
95
  type: :development
96
96
  prerelease: false
97
97
  version_requirements: !ruby/object:Gem::Requirement
98
98
  requirements:
99
- - - "~>"
99
+ - - ">="
100
100
  - !ruby/object:Gem::Version
101
101
  version: 0.14.2
102
102
  - !ruby/object:Gem::Dependency
@@ -204,7 +204,6 @@ files:
204
204
  - lib/unparser/cli.rb
205
205
  - lib/unparser/color.rb
206
206
  - lib/unparser/comments.rb
207
- - lib/unparser/concord.rb
208
207
  - lib/unparser/constants.rb
209
208
  - lib/unparser/diff.rb
210
209
  - lib/unparser/dsl.rb
@@ -294,10 +293,11 @@ files:
294
293
  - lib/unparser/writer/send/conditional.rb
295
294
  - lib/unparser/writer/send/regular.rb
296
295
  - lib/unparser/writer/send/unary.rb
297
- homepage: http://github.com/mbj/unparser
296
+ homepage: https://github.com/mbj/unparser
298
297
  licenses:
299
298
  - MIT
300
299
  metadata:
300
+ homepage_uri: https://github.com/mbj/unparser
301
301
  bug_tracker_uri: https://github.com/mbj/unparser/issues
302
302
  changelog_uri: https://github.com/mbj/unparser/blob/main/Changelog.md
303
303
  funding_uri: https://github.com/sponsors/mbj
@@ -310,14 +310,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
310
310
  requirements:
311
311
  - - ">="
312
312
  - !ruby/object:Gem::Version
313
- version: '3.2'
313
+ version: '3.3'
314
314
  required_rubygems_version: !ruby/object:Gem::Requirement
315
315
  requirements:
316
316
  - - ">="
317
317
  - !ruby/object:Gem::Version
318
318
  version: '0'
319
319
  requirements: []
320
- rubygems_version: 4.0.3
320
+ rubygems_version: 4.0.8
321
321
  specification_version: 4
322
322
  summary: Generate equivalent source for parser gem AST nodes
323
323
  test_files: []
@@ -1,114 +0,0 @@
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