parlour 0.8.0 → 0.8.1

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