visualize_packwerk 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +32 -0
  3. data/lib/visualize_packwerk/graph_interface.rb +17 -0
  4. data/lib/visualize_packwerk/node_interface.rb +29 -0
  5. data/lib/visualize_packwerk/package_graph.rb +48 -0
  6. data/lib/visualize_packwerk/package_node.rb +28 -0
  7. data/lib/visualize_packwerk/package_relationships.rb +158 -0
  8. data/lib/visualize_packwerk/railtie.rb +15 -0
  9. data/lib/visualize_packwerk/tasks/visualize_packwerk.rake +73 -0
  10. data/lib/visualize_packwerk/team_graph.rb +52 -0
  11. data/lib/visualize_packwerk/team_node.rb +27 -0
  12. data/lib/visualize_packwerk.rb +17 -0
  13. data/sorbet/config +2 -0
  14. data/sorbet/rbi/gems/activesupport@7.0.3.1.rbi +76 -0
  15. data/sorbet/rbi/gems/ast@2.4.2.rbi +522 -0
  16. data/sorbet/rbi/gems/code_ownership@1.28.0.rbi +411 -0
  17. data/sorbet/rbi/gems/code_teams@1.0.0.rbi +138 -0
  18. data/sorbet/rbi/gems/coderay@1.1.3.rbi +8 -0
  19. data/sorbet/rbi/gems/concurrent-ruby@1.1.10.rbi +8 -0
  20. data/sorbet/rbi/gems/diff-lcs@1.5.0.rbi +866 -0
  21. data/sorbet/rbi/gems/i18n@1.12.0.rbi +8 -0
  22. data/sorbet/rbi/gems/json@2.6.2.rbi +1423 -0
  23. data/sorbet/rbi/gems/method_source@1.0.0.rbi +8 -0
  24. data/sorbet/rbi/gems/minitest@5.16.2.rbi +9 -0
  25. data/sorbet/rbi/gems/package_protections@1.3.0.rbi +654 -0
  26. data/sorbet/rbi/gems/parallel@1.22.1.rbi +163 -0
  27. data/sorbet/rbi/gems/parse_packwerk@0.11.0.rbi +148 -0
  28. data/sorbet/rbi/gems/parser@3.1.2.0.rbi +4261 -0
  29. data/sorbet/rbi/gems/pry@0.14.1.rbi +8 -0
  30. data/sorbet/rbi/gems/rainbow@3.1.1.rbi +8 -0
  31. data/sorbet/rbi/gems/rake@13.0.6.rbi +1854 -0
  32. data/sorbet/rbi/gems/rbi@0.0.15.rbi +2340 -0
  33. data/sorbet/rbi/gems/regexp_parser@2.5.0.rbi +8 -0
  34. data/sorbet/rbi/gems/rexml@3.2.5.rbi +8 -0
  35. data/sorbet/rbi/gems/rspec-core@3.11.0.rbi +7698 -0
  36. data/sorbet/rbi/gems/rspec-expectations@3.11.0.rbi +6201 -0
  37. data/sorbet/rbi/gems/rspec-mocks@3.11.1.rbi +3625 -0
  38. data/sorbet/rbi/gems/rspec-support@3.11.0.rbi +1176 -0
  39. data/sorbet/rbi/gems/rspec@3.11.0.rbi +40 -0
  40. data/sorbet/rbi/gems/rubocop-ast@1.19.1.rbi +8 -0
  41. data/sorbet/rbi/gems/rubocop-sorbet@0.6.11.rbi +8 -0
  42. data/sorbet/rbi/gems/rubocop@1.33.0.rbi +8 -0
  43. data/sorbet/rbi/gems/ruby-graphviz@1.2.5.rbi +840 -0
  44. data/sorbet/rbi/gems/ruby-progressbar@1.11.0.rbi +8 -0
  45. data/sorbet/rbi/gems/spoom@1.1.11.rbi +1600 -0
  46. data/sorbet/rbi/gems/tapioca@0.8.3.rbi +1978 -0
  47. data/sorbet/rbi/gems/thor@1.2.1.rbi +2921 -0
  48. data/sorbet/rbi/gems/tzinfo@2.0.5.rbi +8 -0
  49. data/sorbet/rbi/gems/unicode-display_width@2.2.0.rbi +8 -0
  50. data/sorbet/rbi/gems/unparser@0.6.5.rbi +8 -0
  51. data/sorbet/rbi/gems/webrick@1.7.0.rbi +1802 -0
  52. data/sorbet/rbi/gems/yard-sorbet@0.6.1.rbi +288 -0
  53. data/sorbet/rbi/gems/yard@0.9.28.rbi +12863 -0
  54. data/sorbet/tapioca/config.yml +13 -0
  55. data/sorbet/tapioca/require.rb +7 -0
  56. metadata +241 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e70be5b42437ab3ffacbbff1a3ec57c1116b8bc5fd1e4fc91163631414a35dae
4
+ data.tar.gz: 7cc7f753055f8f655d0787f3452f3b600eef10182689d637ac2a49eaf96706ff
5
+ SHA512:
6
+ metadata.gz: fe981d2228c1b9039020e5b715cb578b3c5a5a8f6bbade61513151d1a770d06eb327463563b96468e00e0359e7aa6fcadf991d10f03ddec1e923396266c008c0
7
+ data.tar.gz: 8de59866b806300164ccd476d9e481b7aba1ff328d746c246aec49fe3d65c353511dc2db8713807787b1e991c6fcf8040281fee7ff03766c821111950373b1c2
data/README.md ADDED
@@ -0,0 +1,32 @@
1
+ # visualize_packwerk
2
+
3
+ This pack contains rake tasks to help visualize relationships between packwerk packs.
4
+
5
+ # Usage
6
+ ## Building a package graph for a selection of packages (owned by 5 teams max)
7
+ ```
8
+ bin/rails visualize_packwerk:package_relationships['packs/pack1','packs/pack2']
9
+ ```
10
+
11
+ # Building a package graph for specific teams (5 teams max)
12
+ ```
13
+ bin/rails visualize_packwerk:package_relationships_for_teams['Team1','Team2']
14
+ ```
15
+
16
+ # Building a package graph for all packages (this is slow and produces a huge file)
17
+ ```
18
+ bin/rails visualize_packwerk:package_relationships
19
+ ```
20
+
21
+ # Building a TEAM graph for specific teams
22
+ ```
23
+ bin/rails visualize_packwerk:team_relationships['Team1','Team2']
24
+ ```
25
+
26
+ # Building a TEAM graph for all teams (this is slow and produces a huge file)
27
+ ```
28
+ bin/rails visualize_packwerk:team_relationships
29
+ ```
30
+
31
+ # Want to change something or add a feature?
32
+ Submit a PR or post an issue!
@@ -0,0 +1,17 @@
1
+ # typed: strict
2
+
3
+ module VisualizePackwerk
4
+ # This stores graphviz-independent views of our package graph.
5
+ # It should be optimized for fast lookup (leveraging internal indexes, which are stable due to the immutability of the package nodes)
6
+ # A `TeamGraph` should be able to consume this and basically just create a reduced version
7
+ # Lastly, each one should implement a common interface, and graphviz should use that interface and take in either types of graph via the interface
8
+ module GraphInterface
9
+ extend T::Sig
10
+ extend T::Helpers
11
+ interface!
12
+
13
+ sig { abstract.returns(T::Set[NodeInterface]) }
14
+ def nodes
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,29 @@
1
+ # typed: strict
2
+
3
+ module VisualizePackwerk
4
+ module NodeInterface
5
+ extend T::Sig
6
+ extend T::Helpers
7
+ interface!
8
+
9
+ sig { abstract.returns(String) }
10
+ def name
11
+ end
12
+
13
+ sig { abstract.returns(String) }
14
+ def group_name
15
+ end
16
+
17
+ sig { abstract.returns(T::Hash[String, Integer]) }
18
+ def violations_by_node_name
19
+ end
20
+
21
+ sig { abstract.returns(T::Array[String]) }
22
+ def dependencies
23
+ end
24
+
25
+ sig { abstract.params(node_name: String).returns(T::Boolean) }
26
+ def depends_on?(node_name)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,48 @@
1
+ # typed: strict
2
+
3
+ module VisualizePackwerk
4
+ class PackageGraph
5
+ extend T::Sig
6
+ include GraphInterface
7
+
8
+ sig { returns(T::Set[PackageNode]) }
9
+ attr_reader :package_nodes
10
+
11
+ sig { override.returns(T::Set[NodeInterface]) }
12
+ def nodes
13
+ package_nodes
14
+ end
15
+
16
+ sig { params(package_nodes: T::Set[PackageNode]).void }
17
+ def initialize(package_nodes:)
18
+ @package_nodes = package_nodes
19
+ @index_by_name = T.let({}, T::Hash[String, PackageNode])
20
+ end
21
+
22
+ sig { returns(PackageGraph) }
23
+ def self.construct
24
+ package_nodes = Set.new
25
+ ParsePackwerk.all.each do |p|
26
+ # We could consider ignoring the root!
27
+ # We would also need to ignore it when parsing PackageNodes.
28
+ # next if p.name == ParsePackwerk::ROOT_PACKAGE_NAME
29
+ owner = CodeOwnership.for_package(p)
30
+ violations_by_package = PackageProtections::ProtectedPackage.from(p).violations.group_by(&:to_package_name).transform_values(&:count)
31
+
32
+ package_nodes << PackageNode.new(
33
+ name: p.name,
34
+ team_name: owner&.name || 'Unknown',
35
+ violations_by_package: violations_by_package,
36
+ dependencies: Set.new(p.dependencies)
37
+ )
38
+ end
39
+
40
+ PackageGraph.new(package_nodes: package_nodes)
41
+ end
42
+
43
+ sig { params(name: String).returns(PackageNode) }
44
+ def package_by_name(name)
45
+ @index_by_name[name] ||= T.must(package_nodes.find { |node| node.name == name })
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,28 @@
1
+ # typed: strict
2
+
3
+ module VisualizePackwerk
4
+ class PackageNode < T::Struct
5
+ extend T::Sig
6
+ include NodeInterface
7
+
8
+ const :name, String
9
+ const :team_name, String
10
+ const :violations_by_package, T::Hash[String, Integer]
11
+ const :dependencies, T::Set[String]
12
+
13
+ sig { override.returns(T::Hash[String, Integer]) }
14
+ def violations_by_node_name
15
+ violations_by_package
16
+ end
17
+
18
+ sig { override.returns(String) }
19
+ def group_name
20
+ team_name
21
+ end
22
+
23
+ sig { override.params(node_name: String).returns(T::Boolean) }
24
+ def depends_on?(node_name)
25
+ dependencies.include?(node_name) || (violations_by_package[node_name] || 0) > 0
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,158 @@
1
+ # typed: strict
2
+
3
+ module VisualizePackwerk
4
+ class PackageRelationships
5
+ extend T::Sig
6
+
7
+ OUTPUT_FILENAME = T.let('packwerk.png'.freeze, String)
8
+
9
+ sig { void }
10
+ def initialize
11
+ @colors_by_team = T.let({}, T::Hash[String, String])
12
+ @remaining_colors = T.let(
13
+ [
14
+ # Found using https://htmlcolorcodes.com/color-picker/
15
+ '#77EE77', # green
16
+ '#DFEE77', # yellow
17
+ '#77EEE6', # teal
18
+ '#EEC077', # orange
19
+ '#EE77BF', # pink
20
+ '#EE6F6F', # red
21
+ '#ED6EDE', # magenta
22
+ '#8E8CFE', # blue
23
+ '#EEA877', # red-orange
24
+ ], T::Array[String]
25
+ )
26
+ end
27
+
28
+ sig { params(teams: T::Array[CodeTeams::Team]).void }
29
+ def create_package_graph_for_teams!(teams)
30
+ packages = ParsePackwerk.all.select do |package|
31
+ teams.map(&:name).include?(CodeOwnership.for_package(package)&.name)
32
+ end
33
+
34
+ create_package_graph!(packages)
35
+ end
36
+
37
+ sig { params(teams: T::Array[CodeTeams::Team], show_all_teams: T::Boolean).void }
38
+ def create_team_graph!(teams, show_all_teams: false)
39
+ package_graph = PackageGraph.construct
40
+ team_graph = TeamGraph.from_package_graph(package_graph)
41
+ highlighted_node_names = teams.map(&:name)
42
+
43
+ draw_graph!(team_graph, highlighted_node_names, show_all_nodes: show_all_teams)
44
+ end
45
+
46
+ sig { params(packages: T::Array[ParsePackwerk::Package], show_all_packs: T::Boolean).void }
47
+ def create_package_graph!(packages, show_all_packs: false)
48
+ graph = PackageGraph.construct
49
+ highlighted_node_names = packages.map(&:name)
50
+ draw_graph!(graph, highlighted_node_names, show_all_nodes: show_all_packs)
51
+ end
52
+
53
+ sig { params(packages: T::Array[ParsePackwerk::Package], show_all_nodes: T::Boolean).void }
54
+ def create_graph!(packages, show_all_nodes: false)
55
+ graph = PackageGraph.construct
56
+ highlighted_node_names = packages.map(&:name)
57
+ draw_graph!(graph, highlighted_node_names, show_all_nodes: show_all_nodes)
58
+ end
59
+
60
+ sig { params(graph: GraphInterface, highlighted_node_names: T::Array[String], show_all_nodes: T::Boolean).void }
61
+ def draw_graph!(graph, highlighted_node_names, show_all_nodes: false)
62
+ # SFDP looks better than dot in some cases, but less good in other cases.
63
+ # If your visualization looks bad, change the layout to other_layout!
64
+ # https://graphviz.org/docs/layouts/
65
+ default_layout = :dot
66
+ # other_layout = :sfdp
67
+ graphviz_graph = GraphViz.new(:G, type: :digraph, dpi: 100, layout: default_layout)
68
+
69
+ # Create graph nodes
70
+ graphviz_nodes = T.let({}, T::Hash[String, GraphViz::Node])
71
+
72
+ nodes_to_draw = graph.nodes
73
+
74
+ nodes_to_draw.each do |node|
75
+ next unless highlighted_node_names.any? { |highlighted_node_name| node.depends_on?(highlighted_node_name) } || highlighted_node_names.include?(node.name)
76
+
77
+ highlight_node = highlighted_node_names.include?(node.name) && !show_all_nodes
78
+ graphviz_nodes[node.name] = add_node(node, graphviz_graph, highlight_node)
79
+ end
80
+
81
+ max_edge_width = 10
82
+
83
+ # Draw all edges
84
+ nodes_to_draw.each do |node|
85
+ node.dependencies.each do |to_node|
86
+ next unless highlighted_node_names.include?(to_node)
87
+
88
+ graphviz_graph.add_edges(
89
+ graphviz_nodes[node.name],
90
+ graphviz_nodes[to_node],
91
+ { color: 'darkgreen' }
92
+ )
93
+ end
94
+
95
+ node.violations_by_node_name.each do |to_node_name, violation_count|
96
+ next unless highlighted_node_names.include?(to_node_name)
97
+
98
+ edge_width = [
99
+ [(violation_count / 5).to_i, 1].max, # rubocop:disable Lint/NumberConversion
100
+ max_edge_width,
101
+ ].min
102
+
103
+ graphviz_graph.add_edges(
104
+ graphviz_nodes[node.name],
105
+ graphviz_nodes[to_node_name],
106
+ { color: 'red', penwidth: edge_width }
107
+ )
108
+ end
109
+ end
110
+
111
+ # Save graph to filesystem
112
+ puts "Outputting to: #{OUTPUT_FILENAME}"
113
+ graphviz_graph.output(png: OUTPUT_FILENAME)
114
+ puts 'Finished!'
115
+ end
116
+
117
+ sig { params(node: NodeInterface, graph: GraphViz, highlight_node: T::Boolean).returns(GraphViz::Node) }
118
+ def add_node(node, graph, highlight_node)
119
+ default_node_options = {
120
+ fontsize: 26.0,
121
+ fontcolor: 'white',
122
+ fillcolor: 'black',
123
+ color: 'black',
124
+ height: 1.0,
125
+ style: 'filled, rounded',
126
+ shape: 'box',
127
+ }
128
+
129
+ node_options = if highlight_node
130
+ default_node_options.merge(
131
+ fillcolor: highlight_by_group(node),
132
+ color: highlight_by_group(node),
133
+ fontcolor: 'black'
134
+ )
135
+ else
136
+ default_node_options
137
+ end
138
+
139
+ graph.add_nodes(node.name, **node_options)
140
+ end
141
+
142
+ sig { params(node: NodeInterface).returns(String) }
143
+ def highlight_by_group(node)
144
+ highlighted_package_color = @colors_by_team[node.group_name]
145
+ if !highlighted_package_color
146
+ highlighted_package_color = @remaining_colors.first
147
+ raise 'Can only color nodes a max of 5 unique colors for now' if highlighted_package_color.nil?
148
+
149
+ @remaining_colors.delete(highlighted_package_color)
150
+ @colors_by_team[node.group_name] = highlighted_package_color
151
+ end
152
+
153
+ highlighted_package_color
154
+ end
155
+ end
156
+
157
+ private_constant :PackageRelationships
158
+ end
@@ -0,0 +1,15 @@
1
+ # typed: ignore
2
+
3
+ require 'visualize_packwerk'
4
+ require 'rails'
5
+
6
+ module VisualizePackwerk
7
+ class Railtie < Rails::Railtie
8
+ railtie_name :visualize_packwerk
9
+
10
+ rake_tasks do
11
+ path = File.expand_path(__dir__)
12
+ Dir.glob("#{path}/tasks/visualize_packwerk.rake").each { |f| load f }
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,73 @@
1
+ # typed: strict
2
+
3
+ module VisualizePackwerk
4
+ class TaskLoader
5
+ include Rake::DSL
6
+ extend T::Sig
7
+
8
+ sig { void }
9
+ def create_tasks!
10
+ namespace(:visualize_packwerk) do
11
+ # This creates the array of symbols that are needed to declare an argument to a rake task
12
+ package_args = (1..100).map { |i| "package#{i}".to_sym }
13
+
14
+ desc('Graph packages')
15
+ task(:package_relationships, package_args => :environment) do |_task, args|
16
+ show_all_packs = args.to_hash.values.none?
17
+ packages = if show_all_packs
18
+ ParsePackwerk.all
19
+ else
20
+ args.to_hash.values.map do |pack_name|
21
+ found_package = ParsePackwerk.all.find { |p| p.name == pack_name }
22
+ if found_package.nil?
23
+ abort "Could not find pack with name: #{pack_name}"
24
+ end
25
+
26
+ found_package
27
+ end
28
+ end
29
+
30
+ PackageRelationships.new.create_package_graph!(packages, show_all_packs: show_all_packs)
31
+ end
32
+
33
+ # This creates the array of symbols that are needed to declare an argument to a rake task
34
+ team_args = (1..5).map { |i| "team#{i}".to_sym }
35
+
36
+ desc('Graph packages for teams')
37
+ task(:package_relationships_for_teams, team_args => :environment) do |_task, args|
38
+ teams = args.to_hash.values.map do |team_name|
39
+ team = CodeTeams.find(team_name)
40
+ if team.nil?
41
+ abort("Could not find team with name: #{team_name}. Check your config/teams/subdirectory/team.yml for correct team spelling, e.g. `Product Infrastructure`")
42
+ end
43
+
44
+ team
45
+ end
46
+
47
+ PackageRelationships.new.create_package_graph_for_teams!(teams)
48
+ end
49
+
50
+ desc('Graph team relationships')
51
+ task(:team_relationships, team_args => :environment) do |_task, args|
52
+ show_all_teams = args.to_hash.values.none?
53
+ teams = if show_all_teams
54
+ CodeTeams.all
55
+ else
56
+ args.to_hash.values.map do |team_name|
57
+ team = CodeTeams.find(team_name)
58
+ if team.nil?
59
+ abort("Could not find team with name: #{team_name}. Check your config/teams/subdirectory/team.yml for correct team spelling, e.g. `Product Infrastructure`")
60
+ end
61
+
62
+ team
63
+ end
64
+ end
65
+
66
+ PackageRelationships.new.create_team_graph!(teams, show_all_teams: show_all_teams)
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ VisualizePackwerk::TaskLoader.new.create_tasks!
@@ -0,0 +1,52 @@
1
+ # typed: strict
2
+
3
+ module VisualizePackwerk
4
+ #
5
+ # A team graph reduces a PackageGraph by aggregating over packages owned by teams
6
+ #
7
+ class TeamGraph
8
+ extend T::Sig
9
+ include GraphInterface
10
+
11
+ sig { override.returns(T::Set[NodeInterface]) }
12
+ def nodes
13
+ @team_nodes
14
+ end
15
+
16
+ sig { params(team_nodes: T::Set[TeamNode]).void }
17
+ def initialize(team_nodes:)
18
+ @team_nodes = team_nodes
19
+ end
20
+
21
+ sig { params(package_graph: PackageGraph).returns(TeamGraph) }
22
+ def self.from_package_graph(package_graph)
23
+ team_nodes = T.let(Set.new, T::Set[TeamNode])
24
+ package_graph.package_nodes.group_by(&:team_name).each do |team, package_nodes_for_team|
25
+ violations_by_team = {}
26
+ package_nodes_for_team.map(&:violations_by_package).each do |new_violations_by_package|
27
+ new_violations_by_package.each do |pack_name, count|
28
+ # We first get the pack owner of the violated package
29
+ other_team = package_graph.package_by_name(pack_name).team_name
30
+ violations_by_team[other_team] ||= 0
31
+ # Then we add the violations on that team together
32
+ # TODO: We may want to ignore this if team == other_team to avoid arrows pointing to self, but maybe not!
33
+ violations_by_team[other_team] += count
34
+ end
35
+ end
36
+
37
+ dependencies = Set.new
38
+ package_nodes_for_team.map(&:dependencies).reduce(Set.new, :+).each do |dependency|
39
+ dependencies << package_graph.package_by_name(dependency).team_name
40
+ end
41
+
42
+ team_nodes << TeamNode.new(
43
+ name: team,
44
+ violations_by_team: violations_by_team,
45
+ dependencies: dependencies
46
+ )
47
+ end
48
+
49
+ TeamGraph.new(team_nodes: team_nodes)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,27 @@
1
+ # typed: strict
2
+
3
+ module VisualizePackwerk
4
+ class TeamNode < T::Struct
5
+ extend T::Sig
6
+ include NodeInterface
7
+
8
+ const :name, String
9
+ const :violations_by_team, T::Hash[String, Integer]
10
+ const :dependencies, T::Set[String]
11
+
12
+ sig { override.returns(T::Hash[String, Integer]) }
13
+ def violations_by_node_name
14
+ violations_by_team
15
+ end
16
+
17
+ sig { override.returns(String) }
18
+ def group_name
19
+ name
20
+ end
21
+
22
+ sig { override.params(node_name: String).returns(T::Boolean) }
23
+ def depends_on?(node_name)
24
+ dependencies.include?(node_name) || (violations_by_node_name[node_name] || 0) > 0
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,17 @@
1
+ # typed: strict
2
+
3
+ module VisualizePackwerk
4
+ require 'visualize_packwerk/railtie' if defined?(Rails)
5
+ require 'parse_packwerk'
6
+ require 'code_ownership'
7
+ require 'package_protections'
8
+ require 'graphviz'
9
+
10
+ require 'visualize_packwerk/node_interface'
11
+ require 'visualize_packwerk/graph_interface'
12
+ require 'visualize_packwerk/team_node'
13
+ require 'visualize_packwerk/package_node'
14
+ require 'visualize_packwerk/team_graph'
15
+ require 'visualize_packwerk/package_graph'
16
+ require 'visualize_packwerk/package_relationships'
17
+ end
data/sorbet/config ADDED
@@ -0,0 +1,2 @@
1
+ --dir
2
+ .
@@ -0,0 +1,76 @@
1
+ # typed: false
2
+
3
+ # DO NOT EDIT MANUALLY
4
+ # This is an autogenerated file for types exported from the `activesupport` gem.
5
+ # Please instead update this file by running `bin/tapioca gem activesupport`.
6
+
7
+ class FalseClass
8
+ include ::JSON::Ext::Generator::GeneratorMethods::FalseClass
9
+ end
10
+
11
+ class Float < ::Numeric
12
+ include ::JSON::Ext::Generator::GeneratorMethods::Float
13
+ end
14
+
15
+ class IO
16
+ include ::Enumerable
17
+ include ::File::Constants
18
+ end
19
+
20
+ class IO::ConsoleMode
21
+ def echo=(_arg0); end
22
+ def raw(*_arg0); end
23
+ def raw!(*_arg0); end
24
+
25
+ private
26
+
27
+ def initialize_copy(_arg0); end
28
+ end
29
+
30
+ class IO::EAGAINWaitReadable < ::Errno::EAGAIN
31
+ include ::IO::WaitReadable
32
+ end
33
+
34
+ class IO::EAGAINWaitWritable < ::Errno::EAGAIN
35
+ include ::IO::WaitWritable
36
+ end
37
+
38
+ class IO::EINPROGRESSWaitReadable < ::Errno::EINPROGRESS
39
+ include ::IO::WaitReadable
40
+ end
41
+
42
+ class IO::EINPROGRESSWaitWritable < ::Errno::EINPROGRESS
43
+ include ::IO::WaitWritable
44
+ end
45
+
46
+ IO::EWOULDBLOCKWaitReadable = IO::EAGAINWaitReadable
47
+ IO::EWOULDBLOCKWaitWritable = IO::EAGAINWaitWritable
48
+
49
+ class Integer < ::Numeric
50
+ include ::JSON::Ext::Generator::GeneratorMethods::Integer
51
+ end
52
+
53
+ class NameError < ::StandardError
54
+ include ::DidYouMean::Correctable
55
+ end
56
+
57
+ class NilClass
58
+ include ::JSON::Ext::Generator::GeneratorMethods::NilClass
59
+ end
60
+
61
+ class Numeric
62
+ include ::Comparable
63
+ end
64
+
65
+ class Symbol
66
+ include ::Comparable
67
+ end
68
+
69
+ class TrueClass
70
+ include ::JSON::Ext::Generator::GeneratorMethods::TrueClass
71
+ end
72
+
73
+ class URI::Generic
74
+ include ::URI::RFC2396_REGEXP
75
+ include ::URI
76
+ end