metric_fu 2.1.1 → 2.1.3.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. data/.gitignore +20 -0
  2. data/.travis.yml +5 -0
  3. data/Gemfile +5 -0
  4. data/HISTORY +21 -1
  5. data/Manifest.txt +25 -0
  6. data/README.md +61 -0
  7. data/Rakefile +15 -9
  8. data/TODO +2 -0
  9. data/bin/metric_fu +4 -0
  10. data/config/roodi_config.yml +22 -0
  11. data/home_page/back_all.jpg +0 -0
  12. data/home_page/churn.gif +0 -0
  13. data/home_page/flay.gif +0 -0
  14. data/home_page/flog.gif +0 -0
  15. data/home_page/footer.gif +0 -0
  16. data/home_page/header.jpg +0 -0
  17. data/home_page/hotspot.gif +0 -0
  18. data/home_page/img09.gif +0 -0
  19. data/home_page/index.html +305 -0
  20. data/home_page/rcov.gif +0 -0
  21. data/home_page/reek.gif +0 -0
  22. data/home_page/roodi.gif +0 -0
  23. data/home_page/saikuro.gif +0 -0
  24. data/home_page/stats.gif +0 -0
  25. data/home_page/styles.css +245 -0
  26. data/home_page/title.gif +0 -0
  27. data/home_page/title_back.gif +0 -0
  28. data/lib/{base/configuration.rb → configuration.rb} +45 -17
  29. data/lib/data_structures/careful_array.rb +9 -0
  30. data/lib/{base → data_structures}/code_issue.rb +17 -16
  31. data/lib/data_structures/grouping.rb +40 -0
  32. data/lib/{base → data_structures}/line_numbers.rb +23 -14
  33. data/lib/{base → data_structures}/location.rb +3 -1
  34. data/lib/{base → data_structures}/ranking.rb +0 -0
  35. data/lib/data_structures/record.rb +43 -0
  36. data/lib/{base → data_structures}/table.rb +6 -2
  37. data/lib/errors/analysis_error.rb +1 -0
  38. data/lib/initial_requires.rb +25 -0
  39. data/lib/load_files.rb +39 -0
  40. data/lib/logging/mf_debugger.rb +24 -0
  41. data/lib/{base/md5_tracker.rb → md5_tracker.rb} +0 -0
  42. data/lib/metric_fu.rb +55 -37
  43. data/lib/{base → metrics}/base_template.rb +47 -16
  44. data/lib/{generators → metrics/churn}/churn.rb +0 -0
  45. data/lib/{base → metrics/churn}/churn_analyzer.rb +0 -0
  46. data/lib/{templates/awesome → metrics/churn/template_awesome}/churn.html.erb +0 -0
  47. data/lib/{templates/standard → metrics/churn/template_standard}/churn.html.erb +0 -0
  48. data/lib/{generators → metrics/flay}/flay.rb +0 -0
  49. data/lib/{base → metrics/flay}/flay_analyzer.rb +0 -0
  50. data/lib/{graphs → metrics/flay}/flay_grapher.rb +0 -0
  51. data/lib/{templates/awesome → metrics/flay/template_awesome}/flay.html.erb +0 -0
  52. data/lib/{templates/standard → metrics/flay/template_standard}/flay.html.erb +0 -0
  53. data/lib/{generators → metrics/flog}/flog.rb +2 -0
  54. data/lib/{base → metrics/flog}/flog_analyzer.rb +0 -0
  55. data/lib/{graphs → metrics/flog}/flog_grapher.rb +0 -0
  56. data/lib/{templates/awesome → metrics/flog/template_awesome}/flog.html.erb +0 -0
  57. data/lib/{templates/standard → metrics/flog/template_standard}/flog.html.erb +0 -0
  58. data/lib/{base → metrics}/generator.rb +0 -0
  59. data/lib/{base → metrics}/graph.rb +0 -0
  60. data/lib/{generators → metrics/hotspots}/hotspots.rb +0 -0
  61. data/lib/{templates/awesome → metrics/hotspots/template_awesome}/hotspots.html.erb +0 -0
  62. data/lib/{templates/standard → metrics/hotspots/template_standard}/hotspots.html.erb +0 -0
  63. data/lib/{base → metrics}/metric_analyzer.rb +4 -80
  64. data/lib/{generators → metrics/rails_best_practices}/rails_best_practices.rb +0 -0
  65. data/lib/{graphs → metrics/rails_best_practices}/rails_best_practices_grapher.rb +0 -0
  66. data/lib/{templates/awesome → metrics/rails_best_practices/template_awesome}/rails_best_practices.html.erb +1 -1
  67. data/lib/{templates/standard → metrics/rails_best_practices/template_standard}/rails_best_practices.html.erb +1 -1
  68. data/lib/{generators → metrics/rcov}/rcov.rb +5 -3
  69. data/lib/{base → metrics/rcov}/rcov_analyzer.rb +1 -1
  70. data/lib/{graphs → metrics/rcov}/rcov_grapher.rb +0 -0
  71. data/lib/{templates/awesome → metrics/rcov/template_awesome}/rcov.html.erb +0 -0
  72. data/lib/{templates/standard → metrics/rcov/template_standard}/rcov.html.erb +0 -0
  73. data/lib/{generators → metrics/reek}/reek.rb +3 -2
  74. data/lib/{base → metrics/reek}/reek_analyzer.rb +1 -0
  75. data/lib/{graphs → metrics/reek}/reek_grapher.rb +0 -0
  76. data/lib/{templates/awesome → metrics/reek/template_awesome}/reek.html.erb +0 -0
  77. data/lib/{templates/standard → metrics/reek/template_standard}/reek.html.erb +0 -0
  78. data/lib/{generators → metrics/roodi}/roodi.rb +0 -0
  79. data/lib/{base → metrics/roodi}/roodi_analyzer.rb +0 -0
  80. data/lib/{graphs → metrics/roodi}/roodi_grapher.rb +0 -0
  81. data/lib/{templates/awesome → metrics/roodi/template_awesome}/roodi.html.erb +0 -0
  82. data/lib/{templates/standard → metrics/roodi/template_standard}/roodi.html.erb +0 -0
  83. data/lib/{generators → metrics/saikuro}/saikuro.rb +4 -2
  84. data/lib/{base → metrics/saikuro}/saikuro_analyzer.rb +0 -0
  85. data/lib/{templates/awesome → metrics/saikuro/template_awesome}/saikuro.html.erb +0 -0
  86. data/lib/{templates/standard → metrics/saikuro/template_standard}/saikuro.html.erb +0 -0
  87. data/lib/{generators → metrics/stats}/stats.rb +0 -0
  88. data/lib/{base → metrics/stats}/stats_analyzer.rb +0 -0
  89. data/lib/{graphs → metrics/stats}/stats_grapher.rb +0 -0
  90. data/lib/{templates/awesome → metrics/stats/template_awesome}/stats.html.erb +0 -0
  91. data/lib/{templates/standard → metrics/stats/template_standard}/stats.html.erb +0 -0
  92. data/lib/{graphs → reporting/graphs}/engines/bluff.rb +0 -0
  93. data/lib/{graphs → reporting/graphs}/engines/gchart.rb +0 -0
  94. data/lib/{graphs → reporting/graphs}/grapher.rb +0 -0
  95. data/lib/{base → reporting}/report.rb +2 -0
  96. data/lib/{templates → reporting/templates}/awesome/awesome_template.rb +28 -7
  97. data/lib/{templates → reporting/templates}/awesome/css/buttons.css +0 -0
  98. data/lib/{templates → reporting/templates}/awesome/css/default.css +0 -0
  99. data/lib/{templates → reporting/templates}/awesome/css/integrity.css +0 -0
  100. data/lib/{templates → reporting/templates}/awesome/css/reset.css +0 -0
  101. data/lib/{templates → reporting/templates}/awesome/css/syntax.css +0 -0
  102. data/lib/{templates → reporting/templates}/awesome/index.html.erb +0 -0
  103. data/lib/{templates → reporting/templates}/awesome/layout.html.erb +0 -0
  104. data/lib/{templates → reporting/templates}/javascripts/bluff-min.js +0 -0
  105. data/lib/{templates → reporting/templates}/javascripts/excanvas.js +0 -0
  106. data/lib/{templates → reporting/templates}/javascripts/js-class.js +0 -0
  107. data/lib/{templates → reporting/templates}/standard/default.css +0 -0
  108. data/lib/{templates → reporting/templates}/standard/index.html.erb +0 -0
  109. data/lib/{templates → reporting/templates}/standard/standard_template.rb +3 -3
  110. data/lib/{base/scoring_strategies.rb → scoring_strategies.rb} +0 -0
  111. data/lib/tasks/metric_fu.rake +36 -0
  112. data/lib/version.rb +3 -0
  113. data/metric_fu.gemspec +65 -0
  114. data/spec/base/base_template_spec.rb +19 -2
  115. data/spec/base/configuration_spec.rb +4 -3
  116. data/spec/base/generator_spec.rb +2 -2
  117. data/spec/base/line_numbers_spec.rb +2 -2
  118. data/spec/base/location_spec.rb +127 -0
  119. data/spec/base/metric_analyzer_spec.rb +452 -0
  120. data/spec/base/ranking_spec.rb +42 -0
  121. data/spec/base/report_spec.rb +1 -1
  122. data/spec/base/table_spec.rb +36 -0
  123. data/spec/generators/hotspots_spec.rb +88 -0
  124. data/spec/generators/rails_best_practices_spec.rb +1 -1
  125. data/spec/generators/rcov_spec.rb +3 -3
  126. data/spec/generators/stats_spec.rb +1 -1
  127. data/spec/spec_helper.rb +4 -1
  128. metadata +466 -309
  129. data/README +0 -29
  130. data/tasks/metric_fu.rake +0 -22
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,245 @@
1
+ /*
2
+ Design by Metamorphosis Design
3
+ http://www.metamorphozis.com
4
+ Released for free under a Creative Commons Attribution 2.5 License
5
+ */
6
+
7
+ a:link {
8
+ color: #3886E0;
9
+ }
10
+
11
+ a:hover, {
12
+ text-decoration: underline;
13
+ color: #FF0000;
14
+ }
15
+
16
+ a:visited {
17
+ color: #3886E0;
18
+ }
19
+
20
+ *
21
+ {
22
+ border: 0;
23
+ margin: 0;
24
+ }
25
+
26
+ body
27
+ {
28
+ background: #ffffff url(back_all.jpg) repeat-x top;
29
+ font: 12px Tahoma, Arial, Helvetica, sans-serif;
30
+ color: #666666;
31
+ margin-top: 10px;
32
+ }
33
+
34
+ #main
35
+ {
36
+ margin: 0 auto;
37
+ width: 912px;
38
+ background: url(table_back.jpg) repeat-y;
39
+ }
40
+
41
+ #header
42
+ {
43
+ background: url(header.jpg) no-repeat;
44
+ width: 912px;
45
+ height: 262px;
46
+ }
47
+
48
+ #logo
49
+ {
50
+ padding-left: 40px;
51
+ text-align: left;
52
+ padding-top: 40px;
53
+ height: 40px;
54
+ }
55
+
56
+ #logo a {
57
+ text-decoration: none;
58
+ text-transform: lowercase;
59
+ font-style: italic;
60
+ font-size: 16px;
61
+ color: #000000;
62
+ font-weight: bold;
63
+ }
64
+
65
+
66
+ #logo H2 a
67
+ {
68
+ font-size: 10px;
69
+ }
70
+
71
+ #buttons
72
+ {
73
+ padding-top: 140px;
74
+ height: 40px;
75
+ padding-left: 120px;
76
+ }
77
+
78
+ #buttons li {
79
+ display: inline;
80
+ display: block;
81
+ float: left;
82
+ height: 30px;
83
+ margin-left: 1px;
84
+ text-align: center;
85
+ text-decoration: none;
86
+ color: #000000;
87
+ font-weight: bold;
88
+ font-size: 16px;
89
+ padding-top: 10px;
90
+ }
91
+
92
+ #buttons a {
93
+ display: block;
94
+ float: left;
95
+ width: 120px;
96
+ height: 30px;
97
+ margin-left: 1px;
98
+ text-align: center;
99
+ text-decoration: none;
100
+ color: #000000;
101
+ font-weight: bold;
102
+ font-size: 16px;
103
+ padding-top: 10px;
104
+
105
+ }
106
+
107
+ #buttons a:hover {
108
+ text-decoration: underline;
109
+ color: #FF0000;
110
+ }
111
+
112
+ #content
113
+ {
114
+ width: 870px;
115
+ padding: 15px;
116
+ }
117
+
118
+ #left
119
+ {
120
+ width: 580px;
121
+ padding: 10px;
122
+ }
123
+
124
+ #left H1
125
+ {
126
+ color: #99A067;
127
+ margin: 0;
128
+ padding: 0;
129
+ font-size: 24px;
130
+ }
131
+ #left H2
132
+ {
133
+ color: #99A067;
134
+ margin: 0;
135
+ padding: 0;
136
+ font-size: 18px;
137
+ padding-top: 10px;
138
+ }
139
+
140
+ #left a
141
+ {
142
+ color: #99A067;
143
+ }
144
+
145
+ #left a:hover, {
146
+ text-decoration: none;
147
+ color: #FF0000;
148
+ }
149
+
150
+ #left a:visited {
151
+ color: #99A067;
152
+ }
153
+
154
+ .small
155
+ {
156
+ margin: 15px;
157
+ padding: 5px;
158
+ border: 1px solid #99A067
159
+ }
160
+
161
+ #right
162
+ {
163
+ float: right;
164
+ width: 254px;
165
+ }
166
+
167
+ #sidebar
168
+ {
169
+ width: 254px;
170
+ }
171
+
172
+ #sidebar ul
173
+ {
174
+ margin: 0;
175
+ padding: 0;
176
+ list-style: none;
177
+ background: url(title_back.gif) no-repeat;
178
+ }
179
+
180
+ #sidebar li
181
+ {
182
+ margin-bottom: 15px;
183
+
184
+ }
185
+
186
+ #sidebar li ul {
187
+ padding: 10px;
188
+ border-top: none;
189
+ }
190
+
191
+ #sidebar li li {
192
+ margin: 0;
193
+ padding: 3px 0;
194
+ }
195
+
196
+
197
+ #sidebar li h2 {
198
+ height: 34px;
199
+ margin: 0;
200
+ padding: 10px 0 0 20px;
201
+ background: #ffffff url(title.gif) no-repeat;
202
+ font-size: 18px;
203
+ color: #000000;
204
+ }
205
+
206
+ #sidebar a:link {
207
+ text-decoration: none;
208
+ }
209
+
210
+ #sidebar a:hover {
211
+ text-decoration: underline;
212
+ }
213
+ #sidebar a:visited {
214
+ text-decoration: none;
215
+ }
216
+
217
+ #sidebar li a {
218
+ padding-left: 10px;
219
+ background: url(img09.gif) no-repeat 1px 5px;
220
+ }
221
+
222
+
223
+ #footer
224
+ {
225
+ background: url(footer.gif) repeat-x;
226
+ height: 52px;
227
+ font-size: 10px;
228
+ color: #99A067;
229
+ padding-top: 20px;
230
+ text-align: center;
231
+ border-top: #99A067 solid 5px;
232
+ }
233
+
234
+ #footer a
235
+ {
236
+ color: #99A067;
237
+ font-size: 10px;
238
+ text-decoration: none;
239
+ }
240
+ .padding
241
+ {
242
+ padding: 10px;
243
+ color:#FF0000;
244
+ font-weight: bold;
245
+ }
Binary file
Binary file
@@ -1,3 +1,5 @@
1
+ require 'fileutils'
2
+ MetricFu.reporting_require { 'templates/awesome/awesome_template' }
1
3
  module MetricFu
2
4
 
3
5
  # A list of metrics which are available in the MetricFu system.
@@ -5,13 +7,24 @@ module MetricFu
5
7
  # These are metrics which have been developed for the system. Of
6
8
  # course, in order to use these metrics, their respective gems must
7
9
  # be installed on the system.
8
- AVAILABLE_METRICS = [:churn, :flog, :flay, :reek,
9
- :roodi, :rcov,
10
- :hotspots]
11
-
12
- AVAILABLE_METRICS << :saikuro unless RUBY_VERSION == '1.9.2'
13
-
14
- AVAILABLE_GRAPHS = [:flog, :flay, :reek, :roodi, :rcov, :rails_best_practices]
10
+ AVAILABLE_METRICS = [:churn,
11
+ :flog,
12
+ :flay,
13
+ :reek,
14
+ :roodi,
15
+ :rcov,
16
+ :hotspots,
17
+ :saikuro
18
+ ]
19
+
20
+ AVAILABLE_GRAPHS = [
21
+ :flog,
22
+ :flay,
23
+ :reek,
24
+ :roodi,
25
+ :rcov,
26
+ :rails_best_practices
27
+ ]
15
28
  AVAILABLE_GRAPH_ENGINES = [:gchart, :bluff]
16
29
 
17
30
  # The @@configuration class variable holds a global type configuration
@@ -99,13 +112,19 @@ module MetricFu
99
112
  # This does the real work of the Configuration class, by setting
100
113
  # up a bunch of instance variables to represent the configuration
101
114
  # of the MetricFu app.
115
+ # TODO review if these code is functionally duplicated in the
116
+ # base generator initialize
102
117
  def reset
103
- @base_directory = ENV['CC_BUILD_ARTIFACTS'] || 'tmp/metric_fu'
104
- @scratch_directory = File.join(@base_directory, 'scratch')
105
- @output_directory = File.join(@base_directory, 'output')
106
- @data_directory = File.join('tmp/metric_fu', '_data')
107
- @metric_fu_root_directory = File.join(File.dirname(__FILE__),
108
- '..', '..')
118
+ @base_directory = MetricFu.artifact_dir
119
+ @scratch_directory = MetricFu.scratch_dir
120
+ @output_directory = MetricFu.output_dir
121
+ @data_directory = MetricFu.data_dir
122
+ # due to behavior differences between ruby 1.8.7 and 1.9.3
123
+ # this is good enough for now
124
+ [@base_directory, @scratch_directory, @output_directory].each do |dir|
125
+ FileUtils.mkdir_p dir
126
+ end
127
+ @metric_fu_root_directory = MetricFu.root_dir
109
128
  @template_directory = File.join(@metric_fu_root_directory,
110
129
  'lib', 'templates')
111
130
  @template_class = AwesomeTemplate
@@ -120,7 +139,7 @@ module MetricFu
120
139
  :config_file_pattern => nil}
121
140
  @roodi = { :dirs_to_roodi => @code_dirs,
122
141
  :roodi_config => nil}
123
- @saikuro = { :output_directory => @scratch_directory + '/saikuro',
142
+ @saikuro = { :output_directory => "#{@scratch_directory}/saikuro",
124
143
  :input_directory => @code_dirs,
125
144
  :cyclo => "",
126
145
  :filter_cyclo => "0",
@@ -131,6 +150,7 @@ module MetricFu
131
150
  @stats = {}
132
151
  @rcov = { :environment => 'test',
133
152
  :test_files => ['test/**/*_test.rb',
153
+ 'spec/spec_helper.rb', # NOTE: ensure it is loaded before the specs
134
154
  'spec/**/*_spec.rb'],
135
155
  :rcov_opts => ["--sort coverage",
136
156
  "--no-html",
@@ -144,12 +164,15 @@ module MetricFu
144
164
  @rails_best_practices = {}
145
165
  @hotspots = {}
146
166
  @file_globs_to_ignore = []
167
+ @link_prefix = nil
168
+
147
169
 
148
170
  @verbose = false
149
171
 
150
172
  @graph_engine = :bluff # can be :bluff or :gchart
151
173
 
152
- @darwin_txmt_protocol_no_thanks = false
174
+ @darwin_txmt_protocol_no_thanks = true
175
+ # uses the CodeRay gem (was syntax gem)
153
176
  @syntax_highlighting = true #Can be set to false to avoid UTF-8 issues with Ruby 1.9.2 and Syntax 1.0
154
177
  end
155
178
 
@@ -165,7 +188,10 @@ module MetricFu
165
188
  # running within rails.
166
189
  def set_metrics
167
190
  if rails?
168
- @metrics = MetricFu::AVAILABLE_METRICS + [:stats, :rails_best_practices]
191
+ @metrics = MetricFu::AVAILABLE_METRICS + [
192
+ :stats,
193
+ :rails_best_practices
194
+ ]
169
195
  else
170
196
  @metrics = MetricFu::AVAILABLE_METRICS
171
197
  end
@@ -173,7 +199,9 @@ module MetricFu
173
199
 
174
200
  def set_graphs
175
201
  if rails?
176
- @graphs = MetricFu::AVAILABLE_GRAPHS + [:stats]
202
+ @graphs = MetricFu::AVAILABLE_GRAPHS + [
203
+ :stats
204
+ ]
177
205
  else
178
206
  @graphs = MetricFu::AVAILABLE_GRAPHS
179
207
  end
@@ -0,0 +1,9 @@
1
+ module CarefulArray
2
+
3
+ def carefully_remove(elements)
4
+ missing_elements = elements - self
5
+ raise "Cannot delete missing elements: #{missing_elements.inspect}" unless missing_elements.empty?
6
+ (self - elements).extend(CarefulArray)
7
+ end
8
+
9
+ end
@@ -1,26 +1,27 @@
1
1
  require 'delegate'
2
- require MetricFu::LIB_ROOT + '/base/metric_analyzer'
3
- require MetricFu::LIB_ROOT + '/base/flog_analyzer'
4
- require MetricFu::LIB_ROOT + '/base/saikuro_analyzer'
5
- require MetricFu::LIB_ROOT + '/base/churn_analyzer'
6
- require MetricFu::LIB_ROOT + '/base/reek_analyzer'
7
- require MetricFu::LIB_ROOT + '/base/flay_analyzer'
8
-
9
- module CarefulArray
10
-
11
- def carefully_remove(elements)
12
- missing_elements = elements - self
13
- raise "Cannot delete missing elements: #{missing_elements.inspect}" unless missing_elements.empty?
14
- (self - elements).extend(CarefulArray)
15
- end
16
2
 
3
+ [ 'metric_analyzer',
4
+ 'flog/flog_analyzer',
5
+ 'saikuro/saikuro_analyzer',
6
+ 'churn/churn_analyzer',
7
+ 'reek/reek_analyzer',
8
+ 'flay/flay_analyzer'].each do |path|
9
+ MetricFu.metrics_require { path }
17
10
  end
11
+ MetricFu.data_structures_require { 'careful_array' }
18
12
 
19
- class CodeIssue < DelegateClass(Record) #DelegateClass(Ruport::Data::Record)
13
+ class CodeIssue < DelegateClass(MetricFu::Record) #DelegateClass(Ruport::Data::Record)
20
14
  include Comparable
21
15
 
22
16
  # TODO: Yuck! 'stat_value' is a column for StatAnalyzer
23
- EXCLUDED_COLUMNS = FlogAnalyzer::COLUMNS + SaikuroAnalyzer::COLUMNS + ['stat_value'] + ChurnAnalyzer::COLUMNS + ReekAnalyzer.new.columns.extend(CarefulArray).carefully_remove(['reek__type_name', 'reek__comparable_message']) + FlayAnalyzer.new.columns.extend(CarefulArray).carefully_remove(['flay_matching_reason'])
17
+ EXCLUDED_COLUMNS =
18
+ FlogAnalyzer::COLUMNS +
19
+ SaikuroAnalyzer::COLUMNS +
20
+ ['stat_value'] +
21
+ ChurnAnalyzer::COLUMNS +
22
+ ReekAnalyzer.new.columns.extend(CarefulArray).carefully_remove(['reek__type_name',
23
+ 'reek__comparable_message']) +
24
+ FlayAnalyzer.new.columns.extend(CarefulArray).carefully_remove(['flay_matching_reason'])
24
25
 
25
26
  def <=>(other)
26
27
  spaceship_for_columns(self.attributes, other)
@@ -0,0 +1,40 @@
1
+ %w(table).each do |path|
2
+ MetricFu.data_structures_require { path }
3
+ end
4
+ module MetricFu
5
+ class Grouping
6
+
7
+ def initialize(table, opts)
8
+ column_name = opts.fetch(:by)
9
+ order = opts.fetch(:order) { nil }
10
+ hash = {}
11
+ if column_name.to_sym == :metric # special optimized case
12
+ hash = table.group_by_metric
13
+ else
14
+ table.each do |row|
15
+ hash[row[column_name]] ||= Table.new(:column_names => row.attributes)
16
+ hash[row[column_name]] << row
17
+ end
18
+ end
19
+ if order
20
+ @arr = hash.sort_by &order
21
+ else
22
+ @arr = hash.to_a
23
+ end
24
+ end
25
+
26
+ def [](key)
27
+ @arr.each do |group_key, table|
28
+ return table if group_key == key
29
+ end
30
+ return nil
31
+ end
32
+
33
+ def each
34
+ @arr.each do |value, rows|
35
+ yield value, rows
36
+ end
37
+ end
38
+
39
+ end
40
+ end