parlour 0.8.0 → 0.8.1

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: 12b7eca4df3f9c2609ae2f8cabbf07b73a26c66f596ce060aea6f9faec5a494d
4
- data.tar.gz: 6ca3cf5d7d22d15fd3270adf78044b4aa8286808074c0e0c9b43b68ef4be0bdb
3
+ metadata.gz: 5a670215d6246dfe4cc4aec9e3dd5121cf1da1357dbc1703a53dd059d3467d47
4
+ data.tar.gz: 6c8fa32d0adb363b72d43e307fb38c443dd469444ffbefddaa561e841b108846
5
5
  SHA512:
6
- metadata.gz: d90cfc6922e9b4ccea622d31d4cdbfe422e6cd8292cdae12a1b2e70ee51bfd1d1779ae66b1b213c14806e3239306f92e149e2d280387127c66147f570d8e198d
7
- data.tar.gz: a9f75203ac84c20e91dd24702c904b79741f1156b4975da43d3078423e316ecb534ae56261a4c949454175ee49ba4d5f44236dcadadcebb6368f00a30d52d937
6
+ metadata.gz: '0089e4ef2b9cf1855bba3e1a8a1a5faeae2a020003c9625ef95e96fb7c6b0293cf44cf8fda4a2a312fe3ea91d9b10e05cd70d83b96cc80eb1354741958210140'
7
+ data.tar.gz: b9554148306f4a0453cf4d6e9244581a6380df6341d0ec88033b91c917ef4a1d9e67f7448cc51758b7ec8c98044583810ccb68ad5a85aa3b221086e9c105844f
@@ -3,6 +3,15 @@ All notable changes to this project will be documented in this file.
3
3
 
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
5
5
 
6
+ ## [0.8.1] - 2019-09-27
7
+ ### Added
8
+ - Running with the PARLOUR_DEBUG environment variable set will now print debug
9
+ output to the console during conflict resolution.
10
+
11
+ ### Fixed
12
+ - Performance is now much faster when the conflict resolver needs to resolve a
13
+ conflict between many identical objects.
14
+
6
15
  ## [0.8.0] - 2019-09-14
7
16
  ### Added
8
17
  - Methods can now have type parameters specified.
data/README.md CHANGED
@@ -152,7 +152,7 @@ _Have you written an awesome Parlour plugin? Please submit a PR to add it to thi
152
152
 
153
153
  - [Sord](https://github.com/AaronC81/sord) - Generate RBIs from YARD documentation
154
154
  - [parlour-datamapper](https://github.com/AaronC81/parlour-datamapper) - Simple plugin for generating DataMapper model types
155
-
155
+ - [sorbet-rails](https://github.com/chanzuckerberg/sorbet-rails) - Generate RBIs for Rails models, routes, mailers, etc.
156
156
 
157
157
  ## Contributing
158
158
 
@@ -3,6 +3,8 @@ require 'sorbet-runtime'
3
3
 
4
4
  require 'parlour/version'
5
5
 
6
+ require 'parlour/debugging'
7
+
6
8
  require 'parlour/kernel_hack'
7
9
 
8
10
  require 'parlour/plugin'
@@ -39,23 +39,49 @@ module Parlour
39
39
  # will be kept, or nil to keep none of them.
40
40
  # @return [void]
41
41
  def resolve_conflicts(namespace, &resolver)
42
+ Debugging.debug_puts(self, Debugging::Tree.begin("Resolving conflicts for #{namespace.name}..."))
43
+
42
44
  # Check for multiple definitions with the same name
43
45
  grouped_by_name_children = namespace.children.group_by(&:name)
44
46
 
45
47
  grouped_by_name_children.each do |name, children|
48
+ Debugging.debug_puts(self, Debugging::Tree.begin("Checking children named #{name}..."))
49
+
46
50
  if children.length > 1
51
+ Debugging.debug_puts(self, Debugging::Tree.here("Possible conflict between #{children.length} objects"))
52
+
47
53
  # Special case: do we have two methods, one of which is a class method
48
54
  # and the other isn't? If so, do nothing - this is fine
49
- next if children.length == 2 &&
55
+ if children.length == 2 &&
50
56
  children.all? { |c| c.is_a?(RbiGenerator::Method) } &&
51
57
  children.count { |c| T.cast(c, RbiGenerator::Method).class_method } == 1
52
58
 
59
+ Debugging.debug_puts(self, Debugging::Tree.end("One is an instance method and one is a class method; no resolution required"))
60
+ next
61
+ end
62
+
53
63
  # Special case: do we have two attributes, one of which is a class
54
64
  # attribute and the other isn't? If so, do nothing - this is fine
55
- next if children.length == 2 &&
65
+ if children.length == 2 &&
56
66
  children.all? { |c| c.is_a?(RbiGenerator::Attribute) } &&
57
67
  children.count { |c| T.cast(c, RbiGenerator::Attribute).class_attribute } == 1
58
68
 
69
+ Debugging.debug_puts(self, Debugging::Tree.end("One is an instance attribute and one is a class attribute; no resolution required"))
70
+ next
71
+ end
72
+
73
+ # Special case: are they all clearly equal? If so, remove all but one
74
+ if all_eql?(children)
75
+ Debugging.debug_puts(self, Debugging::Tree.end("All children are identical"))
76
+
77
+ # All of the children are the same, so this deletes all of them
78
+ namespace.children.delete(T.must(children.first))
79
+
80
+ # Re-add one child
81
+ namespace.children << T.must(children.first)
82
+ next
83
+ end
84
+
59
85
  # We found a conflict!
60
86
  # Start by removing all the conflicting items
61
87
  children.each do |c|
@@ -66,7 +92,8 @@ module Parlour
66
92
  # type of object, so check that first
67
93
  children_type = single_type_of_array(children)
68
94
  unless children_type
69
- # The types aren't the same, so ask the resovler what to do, and
95
+ Debugging.debug_puts(self, Debugging::Tree.end("Children are different types; requesting manual resolution"))
96
+ # The types aren't the same, so ask the resolver what to do, and
70
97
  # insert that (if not nil)
71
98
  choice = resolver.call("Different kinds of definition for the same name", children)
72
99
  namespace.children << choice if choice
@@ -77,21 +104,29 @@ module Parlour
77
104
  first, *rest = children
78
105
  first, rest = T.must(first), T.must(rest)
79
106
  if T.must(first).mergeable?(T.must(rest))
107
+ Debugging.debug_puts(self, Debugging::Tree.end("Children are all mergeable; resolving automatically"))
80
108
  first.merge_into_self(rest)
81
109
  namespace.children << first
82
110
  next
83
111
  end
84
112
 
85
113
  # I give up! Let it be resolved manually somehow
114
+ Debugging.debug_puts(self, Debugging::Tree.end("Unable to resolve automatically; requesting manual resolution"))
86
115
  choice = resolver.call("Can't automatically resolve", children)
87
116
  namespace.children << choice if choice
117
+ else
118
+ Debugging.debug_puts(self, Debugging::Tree.end("No conflicts"))
88
119
  end
89
120
  end
90
121
 
122
+ Debugging.debug_puts(self, Debugging::Tree.here("Resolving children..."))
123
+
91
124
  # Recurse to child namespaces
92
125
  namespace.children.each do |child|
93
126
  resolve_conflicts(child, &resolver) if RbiGenerator::Namespace === child
94
127
  end
128
+
129
+ Debugging.debug_puts(self, Debugging::Tree.end("All children done"))
95
130
  end
96
131
 
97
132
  private
@@ -0,0 +1,122 @@
1
+ # typed: true
2
+ require 'rainbow'
3
+
4
+ module Parlour
5
+ # Contains methods to enable debugging facilities for Parlour.
6
+ module Debugging
7
+ extend T::Sig
8
+
9
+ @debug_mode = !ENV["PARLOUR_DEBUG"].nil?
10
+
11
+ # Set whether debug messages should be printed.
12
+ # @param [Boolean] value True if debug messages will be printed, false
13
+ # otherwise.
14
+ # @return [Boolean] The new value.
15
+ sig { params(value: T::Boolean).returns(T::Boolean) }
16
+ def self.debug_mode=(value)
17
+ @debug_mode = value
18
+ end
19
+
20
+ # Whether debug messages sent by {#debug_puts} should be printed.
21
+ # Defaults to true if the PARLOUR_DEBUG environment variable is set.
22
+ # @return [Boolean] True if debug messages will be printed, false otherwise.
23
+ sig { returns(T::Boolean) }
24
+ def self.debug_mode?
25
+ @debug_mode
26
+ end
27
+
28
+ # Prints a message with a debugging prefix to STDOUT if {#debug_mode?} is
29
+ # true.
30
+ # @params [Object] object The object which is printing this debug message.
31
+ # Callers should pass +self+.
32
+ # @params [String] message The message to print. It should not contain
33
+ # newlines.
34
+ # @return [void]
35
+ sig { params(object: T.untyped, message: String).void }
36
+ def self.debug_puts(object, message)
37
+ return unless debug_mode?
38
+ name = Rainbow("#{name_for_debug_caller(object)}: ").magenta.bright.bold
39
+ prefix = Rainbow("Parlour debug: ").blue.bright.bold
40
+ puts prefix + name + message
41
+ end
42
+
43
+ # Converts the given object into a human-readable prefix to a debug message.
44
+ # For example, passing an instance of {ConflictResolver} returns
45
+ # "conflict resolver". If the object type is unknown, this returns its class
46
+ # name.
47
+ # @param [Object] object The object to convert.
48
+ # @return [String] A string describing the object for {#debug_puts}.
49
+ sig { params(object: T.untyped).returns(String) }
50
+ def self.name_for_debug_caller(object)
51
+ case object
52
+ when ConflictResolver
53
+ "conflict resolver"
54
+ when RbiGenerator
55
+ "RBI generator"
56
+ else
57
+ if ((object < Plugin) rescue false)
58
+ return "plugin #{object.name}"
59
+ end
60
+ object.class.name
61
+ end
62
+ end
63
+
64
+ # A module for generating a globally-consistent, nicely-formatted tree of
65
+ # output using Unicode block characters.
66
+ module Tree
67
+ extend T::Sig
68
+
69
+ # The number of spaces to indent each layer of the tree by. Should be at
70
+ # least 1.
71
+ INDENT_SPACES = 2
72
+
73
+ # The current indent level of the tree.
74
+ @indent_level = 0
75
+
76
+ # Returns a new heading, and then decents the tree one level into it.
77
+ # (That is, future output will go under the new heading.)
78
+ # @param [String] message The heading.
79
+ # @return [String] The line of this tree which should be printed.
80
+ sig { params(message: String).returns(String) }
81
+ def self.begin(message)
82
+ result = line_prefix + '├' + text_prefix + Rainbow(message).green.bright.bold
83
+ @indent_level += 1
84
+ result
85
+ end
86
+
87
+ # Prints a new tree element at the current level.
88
+ # @param [String] message The element.
89
+ # @return [String] The line of this tree which should be printed.
90
+ sig { params(message: String).returns(String) }
91
+ def self.here(message)
92
+ line_prefix + '├' + text_prefix + message
93
+ end
94
+
95
+ # Prints the final tree element at the current level, then ascends one
96
+ # level.
97
+ # @param [String] message The element.
98
+ # @return [String] The line of this tree which should be printed.
99
+ sig { params(message: String).returns(String) }
100
+ def self.end(message)
101
+ result = line_prefix + '└' + text_prefix + message
102
+ @indent_level = [0, @indent_level - 1].max
103
+ result
104
+ end
105
+
106
+ # The prefix which should be printed before anything else on this line of
107
+ # the tree, based on the current indent level.
108
+ # @return [String]
109
+ def self.line_prefix
110
+ @indent_level.times.map { '│' + ' ' * INDENT_SPACES }.join
111
+ end
112
+
113
+ # The horizontal lines which should be printed between the beginning of
114
+ # the current element and its text, based on the specified number of
115
+ # spaces to use for indents.
116
+ # @return [String]
117
+ def self.text_prefix
118
+ '─' * (INDENT_SPACES - 1) + " "
119
+ end
120
+ end
121
+ end
122
+ end
@@ -25,6 +25,7 @@ module Parlour
25
25
  # @param new_plugin [Plugin] The new plugin.
26
26
  # @return [void]
27
27
  def self.inherited(new_plugin)
28
+ Debugging.debug_puts(self, 'Registered')
28
29
  registered_plugins[T.must(new_plugin.name)] = new_plugin
29
30
  end
30
31
 
@@ -54,7 +54,7 @@ module Parlour
54
54
  yield_self(&block) if block
55
55
  end
56
56
 
57
- sig { overridable.params(other: Object).returns(T::Boolean) }
57
+ sig { overridable.params(other: Object).returns(T::Boolean).checked(:never) }
58
58
  # Returns true if this instance is equal to another method.
59
59
  #
60
60
  # @param other [Object] The other instance. If this is not a {Method} (or a
@@ -1,5 +1,5 @@
1
1
  # typed: strong
2
2
  module Parlour
3
3
  # The library version.
4
- VERSION = '0.8.0'
4
+ VERSION = '0.8.1'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: parlour
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aaron Christiansen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-09-14 00:00:00.000000000 Z
11
+ date: 2019-09-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sorbet-runtime
@@ -130,6 +130,7 @@ files:
130
130
  - exe/parlour
131
131
  - lib/parlour.rb
132
132
  - lib/parlour/conflict_resolver.rb
133
+ - lib/parlour/debugging.rb
133
134
  - lib/parlour/kernel_hack.rb
134
135
  - lib/parlour/plugin.rb
135
136
  - lib/parlour/rbi_generator.rb