reportability 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format progress
3
+ --order rand
data/CHANGELOG.md ADDED
@@ -0,0 +1 @@
1
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in bms_booking_lists.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,27 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+ guard 'bundler' do
4
+ watch('Gemfile')
5
+ end
6
+
7
+ group :unit do
8
+ guard 'rspec', :cli => "--color --format nested --fail-fast", :notification => true, :spec_paths => ['spec/lib'],
9
+ :run_all => { :cli => "--color --fail-fast" }, :turnip => true do
10
+ watch(%r{^spec/lib/(.+)_spec\.rb$})
11
+ watch(%r{^spec/lib/(.+)\.feature$})
12
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
13
+ watch('spec/spec_helper.rb') { "spec" }
14
+ end
15
+ end
16
+
17
+ # group :acceptance do
18
+ # guard 'rspec', :all_after_pass => false, :spec_paths => ["spec/acceptance"],
19
+ # :run_all => { :cli => "-I spec/acceptance -r ./spec/acceptance/acceptance_helper.rb" }, :turnip => true,
20
+ # :cli => "-I spec/acceptance --color --format nested --fail-fast -r ./spec/acceptance/acceptance_helper.rb", :notification => true do
21
+ # watch(%r{^spec/acceptance/.+_spec\.rb$})
22
+ # # Turnip features and steps
23
+ # watch(%r{^spec/acceptance/(.+)\.feature$})
24
+ # watch(%r{^spec/acceptance/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
25
+ # end
26
+ # end
27
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Piotr Zolnierek
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Reportability
2
+
3
+ A sweet little gem helping with the display of reports.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'reportability'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install reportability
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ Dir["**/*.rake"].each {|ext| load ext}
4
+
5
+ task :default => [:'spec:unit', :'spec:acceptance']
@@ -0,0 +1,6 @@
1
+ module Reportability
2
+ class InputDataError < StandardError; end
3
+ end
4
+
5
+ require 'reportability/pivot'
6
+ require 'reportability/summary'
@@ -0,0 +1,60 @@
1
+ module Reportability
2
+ class Table
3
+ attr_reader :cols, :rows
4
+ def initialize(args)
5
+ @cols, @rows = args[:cols], args[:rows]
6
+ end
7
+
8
+ def inspect
9
+ lengths = cols.map { |col| max_column_length(col) }
10
+ rows.map do |row|
11
+ "|".tap do |s|
12
+ row.each_index { |i| s << (" %-#{lengths[i]}s |" % row[i].to_s)}
13
+ end
14
+ end.join("\n")
15
+ end
16
+
17
+ def max_column_length(col)
18
+ idx = cols.index(col)
19
+ ([col.to_s] + rows).map { |row| row[idx].to_s.length }.max
20
+ end
21
+ end
22
+
23
+ class Pivot
24
+ attr_accessor :source_data, :pivot, :values
25
+ def project(&block)
26
+ @project = block
27
+ end
28
+
29
+ def new_row(v_group, num_cols)
30
+ Array.new(num_cols) {|e| v_group if e == 0}
31
+ end
32
+
33
+ def call(cols, input)
34
+ if @project
35
+ projection = input.map { |e| @project.call(e) }
36
+ else
37
+ projection = input
38
+ end
39
+ pivot_idx = 0 # cols.index(pivot)
40
+ group_idx = 1 # cols.index(group)
41
+ value_idx = 2 # cols.index(values)
42
+
43
+ out_cols = ['group_by'] + projection.map { |e| e[pivot_idx] }.uniq.sort
44
+ num_cols = out_cols.length
45
+ rows = { nil => out_cols }
46
+
47
+ projection.each do |i|
48
+ raise Reportability::InputDataError, "Invalid row #{i.inspect}" unless i.is_a?(Array) && i.length == 3
49
+ v_group = i[group_idx]
50
+ v_pivot = i[pivot_idx]
51
+ v_value = i[value_idx]
52
+
53
+ row = (rows[v_group] ||= new_row(v_group, num_cols))
54
+ value_col = out_cols.index(v_pivot)
55
+ row[value_col] = v_value if value_col
56
+ end
57
+ t = Table.new :cols => out_cols, :rows => rows.values
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,50 @@
1
+ module Reportability
2
+ class Summary
3
+ # level_fields - group by fields
4
+ # alawys_fields - those must always be present in output
5
+ # value_fields - those are summarized
6
+ def initialize(level_fields, always_fields, value_fields, aggregates={})
7
+ @level_fields = level_fields
8
+ @always_fields = always_fields
9
+ @value_fields = value_fields
10
+ @levels = {}
11
+ @aggregates = Hash.new(default_aggregate).merge(aggregates)
12
+ end
13
+
14
+ def push(row)
15
+ @level_fields.each do |e|
16
+ update_level(e, row)
17
+ end
18
+ end
19
+
20
+ # flattens the output
21
+ def summary
22
+ @levels.map { |k, v| k.merge(v) }
23
+ end
24
+
25
+ def inspect
26
+ @levels
27
+ end
28
+
29
+ private
30
+ def update_level(e, row)
31
+ level_num = @level_fields.index(e)
32
+ key_fields = @level_fields[0..level_num] + @always_fields
33
+ keys = row.select { |k| key_fields.include?(k) }
34
+ level_key = {_level: level_num + 1}.merge(keys)
35
+ values = row.select { |k| @value_fields.include?(k)}
36
+
37
+ v = {level_key => values}
38
+
39
+ @levels.merge!(v) do |key, oldval, newval|
40
+ oldval.merge!(newval) { |k, x, y| @aggregates[k].(x, y)}
41
+ end
42
+ end
43
+
44
+ def default_aggregate
45
+ ->(x,y) { x + y}
46
+ end
47
+
48
+ end
49
+ end
50
+
@@ -0,0 +1,3 @@
1
+ module Reportability
2
+ VERSION = "0.2.0"
3
+ end
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'reportability/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "reportability"
8
+ gem.version = Reportability::VERSION
9
+ gem.authors = ["Piotr Zolnierek"]
10
+ gem.email = ["pz@anixe.pl"]
11
+ gem.description = %q{Reportbility}
12
+ gem.summary = %q{Helps with reports}
13
+ gem.homepage = "http://github.com/pzol/reportability"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ # gem.add_dependency 'activesupport'
21
+ gem.add_dependency 'multi_json'
22
+
23
+ gem.add_development_dependency 'active_support'
24
+ gem.add_development_dependency 'rspec', '>=2.9.0'
25
+ gem.add_development_dependency 'turnip'
26
+ gem.add_development_dependency 'guard'
27
+ gem.add_development_dependency 'guard-rspec'
28
+ gem.add_development_dependency 'guard-bundler'
29
+ gem.add_development_dependency 'growl'
30
+ gem.add_development_dependency 'rake'
31
+ gem.add_development_dependency 'rb-fsevent', '~> 0.9.1'
32
+ end
@@ -0,0 +1,55 @@
1
+ require 'multi_json'
2
+
3
+ step 'I load :name' do |name|
4
+ filename = File.expand_path("../#{name}.json", __FILE__)
5
+ json = IO.read(filename)
6
+ @input = MultiJson.load(json)
7
+ end
8
+
9
+ step 'the json' do |json|
10
+ @input = MultiJson.load(json)
11
+ end
12
+
13
+ step 'I pivot it' do
14
+ r = Reportability::Pivot.new
15
+ @output = r.call [:c, :r, :v], @input
16
+ end
17
+
18
+ require 'active_support/core_ext/hash/slice'
19
+ step 'I magic-pivot it2' do
20
+ r = Reportability::Pivot.new
21
+ r.project do |row|
22
+ [
23
+ row["date"],
24
+ row.slice("_level", "provider", "currency", "country", "tlc"),
25
+ row.slice("count", "value")
26
+ ]
27
+ end
28
+ @output = r.call [:date_booked, :date, :values], @input
29
+ end
30
+
31
+ step 'I magic-pivot it' do
32
+ r = Reportability::Pivot.new
33
+ r.project do |row|
34
+ key = row['key']
35
+ [
36
+ "%4d-%02d" % [key['date_from']['y'], key['date_from']['m']],
37
+ [key['provider'], key['tlc']].join(', '),
38
+ row['value']['count']
39
+ ]
40
+ end
41
+ @output = r.call [:date_booked, :provider_tlc, :count], @input
42
+ end
43
+
44
+ step 'the output is' do |expected_result|
45
+ @output.inspect.should == expected_result
46
+ end
47
+
48
+ step 'the result table is' do |table|
49
+ @output.rows.each_index do |i|
50
+ expected_row = table.raw[i] || []
51
+ expected = expected_row.join(' | ')
52
+ actual = @output.rows[i].join(' | ')
53
+ actual.should == expected
54
+ end
55
+ end
@@ -0,0 +1,442 @@
1
+ [
2
+ {
3
+ "_id": "510419a46dbc545f6f000001",
4
+ "key": {
5
+ "date_from": {
6
+ "y": 2011,
7
+ "m": 7
8
+ },
9
+ "product": "HOTEL",
10
+ "contract": "youtravel",
11
+ "status": "book_confirmed",
12
+ "provider": "HOTEL A34",
13
+ "currency": "EUR",
14
+ "tlc": "GRO"
15
+ },
16
+ "value": {
17
+ "count": 1,
18
+ "price": {
19
+ "type": "NETNET",
20
+ "value": 0.02
21
+ }
22
+ }
23
+ },
24
+ {
25
+ "_id": "510419a46dbc545f6f000002",
26
+ "key": {
27
+ "date_from": {
28
+ "y": 2011,
29
+ "m": 8
30
+ },
31
+ "product": "HOTEL",
32
+ "contract": "test",
33
+ "status": "cancel_confirmed",
34
+ "provider": "HOTELBEDS",
35
+ "currency": "GBP",
36
+ "tlc": "YYY"
37
+ },
38
+ "value": {
39
+ "count": 1,
40
+ "price": {
41
+ "type": "NETNET",
42
+ "value": 45.45
43
+ }
44
+ }
45
+ },
46
+ {
47
+ "_id": "510419a46dbc545f6f000003",
48
+ "key": {
49
+ "date_from": {
50
+ "y": 2011,
51
+ "m": 8
52
+ },
53
+ "product": "HOTEL",
54
+ "contract": "test",
55
+ "status": "cancel_confirmed",
56
+ "provider": "MIKI",
57
+ "currency": "EUR",
58
+ "tlc": "YYY"
59
+ },
60
+ "value": {
61
+ "count": 1,
62
+ "price": {
63
+ "type": "NETNET",
64
+ "value": 0
65
+ }
66
+ }
67
+ },
68
+ {
69
+ "_id": "510419a46dbc545f6f000004",
70
+ "key": {
71
+ "date_from": {
72
+ "y": 2011,
73
+ "m": 8
74
+ },
75
+ "product": "HOTEL",
76
+ "contract": "test",
77
+ "status": "cancel_confirmed",
78
+ "provider": "HOTELBEDS",
79
+ "currency": "EUR",
80
+ "tlc": "YYY"
81
+ },
82
+ "value": {
83
+ "count": 1,
84
+ "price": {
85
+ "type": "NETNET",
86
+ "value": 47.62
87
+ }
88
+ }
89
+ },
90
+ {
91
+ "_id": "510419a46dbc545f6f000005",
92
+ "key": {
93
+ "date_from": {
94
+ "y": 2011,
95
+ "m": 9
96
+ },
97
+ "product": "HOTEL",
98
+ "contract": "test",
99
+ "status": "cancel_confirmed",
100
+ "provider": "MIKI",
101
+ "currency": "EUR",
102
+ "tlc": "YYY"
103
+ },
104
+ "value": {
105
+ "count": 1,
106
+ "price": {
107
+ "type": "NETNET",
108
+ "value": 0
109
+ }
110
+ }
111
+ },
112
+ {
113
+ "_id": "510419a46dbc545f6f000006",
114
+ "key": {
115
+ "date_from": {
116
+ "y": 2011,
117
+ "m": 9
118
+ },
119
+ "product": "HOTEL",
120
+ "contract": "test",
121
+ "status": "cancel_confirmed",
122
+ "provider": "HOTELBEDS",
123
+ "currency": "EUR",
124
+ "tlc": "YYY"
125
+ },
126
+ "value": {
127
+ "count": 3,
128
+ "price": {
129
+ "type": "NETNET",
130
+ "value": 0
131
+ }
132
+ }
133
+ },
134
+ {
135
+ "_id": "510419a46dbc545f6f000007",
136
+ "key": {
137
+ "date_from": {
138
+ "y": 2011,
139
+ "m": 8
140
+ },
141
+ "product": "HOTEL",
142
+ "contract": "test",
143
+ "status": "book_confirmed",
144
+ "provider": "MIKI",
145
+ "currency": "EUR",
146
+ "tlc": "YYY"
147
+ },
148
+ "value": {
149
+ "count": 1,
150
+ "price": {
151
+ "type": "NETNET",
152
+ "value": 38
153
+ }
154
+ }
155
+ },
156
+ {
157
+ "_id": "510419a46dbc545f6f000008",
158
+ "key": {
159
+ "date_from": {
160
+ "y": 2011,
161
+ "m": 9
162
+ },
163
+ "product": "HOTEL",
164
+ "contract": "test",
165
+ "status": "book_confirmed",
166
+ "provider": "MIKI",
167
+ "currency": "EUR",
168
+ "tlc": "YYY"
169
+ },
170
+ "value": {
171
+ "count": 3,
172
+ "price": {
173
+ "type": "NETNET",
174
+ "value": 218.5
175
+ }
176
+ }
177
+ },
178
+ {
179
+ "_id": "510419a46dbc545f6f000009",
180
+ "key": {
181
+ "date_from": {
182
+ "y": 2011,
183
+ "m": 8
184
+ },
185
+ "product": "HOTEL",
186
+ "contract": "test",
187
+ "status": "book_confirmed",
188
+ "provider": "KUONI",
189
+ "currency": "EUR",
190
+ "tlc": "YYY"
191
+ },
192
+ "value": {
193
+ "count": 1,
194
+ "price": {
195
+ "type": "NETNET",
196
+ "value": 102
197
+ }
198
+ }
199
+ },
200
+ {
201
+ "_id": "510419a46dbc545f6f00000a",
202
+ "key": {
203
+ "date_from": {
204
+ "y": 2011,
205
+ "m": 10
206
+ },
207
+ "product": "HOTEL",
208
+ "contract": "test.testroomz",
209
+ "status": "cancel_confirmed",
210
+ "provider": "ROOMZ",
211
+ "currency": "EUR",
212
+ "tlc": "YYY"
213
+ },
214
+ "value": {
215
+ "count": 1,
216
+ "price": {
217
+ "type": "NETNET",
218
+ "value": 0
219
+ }
220
+ }
221
+ },
222
+ {
223
+ "_id": "510419a46dbc545f6f00000b",
224
+ "key": {
225
+ "date_from": {
226
+ "y": 2011,
227
+ "m": 10
228
+ },
229
+ "product": "HOTEL",
230
+ "contract": "test.aerextranettest",
231
+ "status": "cancel_confirmed",
232
+ "provider": "TOURICO",
233
+ "currency": "EUR",
234
+ "tlc": "YYY"
235
+ },
236
+ "value": {
237
+ "count": 1,
238
+ "price": {
239
+ "type": "NETNET",
240
+ "value": 92.04
241
+ }
242
+ }
243
+ },
244
+ {
245
+ "_id": "510419a46dbc545f6f00000c",
246
+ "key": {
247
+ "date_from": {
248
+ "y": 2011,
249
+ "m": 10
250
+ },
251
+ "product": "HOTEL",
252
+ "contract": "test",
253
+ "status": "cancel_confirmed",
254
+ "provider": "AOT",
255
+ "currency": "AUD",
256
+ "tlc": "YYY"
257
+ },
258
+ "value": {
259
+ "count": 2,
260
+ "price": {
261
+ "type": "NETNET",
262
+ "value": 0
263
+ }
264
+ }
265
+ },
266
+ {
267
+ "_id": "510419a46dbc545f6f00000d",
268
+ "key": {
269
+ "date_from": {
270
+ "y": 2011,
271
+ "m": 10
272
+ },
273
+ "product": "HOTEL",
274
+ "contract": "test",
275
+ "status": "cancel_confirmed",
276
+ "provider": "HOTELBEDS",
277
+ "currency": "EUR",
278
+ "tlc": "YYY"
279
+ },
280
+ "value": {
281
+ "count": 1,
282
+ "price": {
283
+ "type": "NETNET",
284
+ "value": 0
285
+ }
286
+ }
287
+ },
288
+ {
289
+ "_id": "510419a46dbc545f6f00000e",
290
+ "key": {
291
+ "date_from": {
292
+ "y": 2011,
293
+ "m": 9
294
+ },
295
+ "product": "HOTEL",
296
+ "contract": "test",
297
+ "status": "cancel_confirmed",
298
+ "provider": "KUONI",
299
+ "currency": "EUR",
300
+ "tlc": "YYY"
301
+ },
302
+ "value": {
303
+ "count": 1,
304
+ "price": {
305
+ "type": "NETNET",
306
+ "value": 0
307
+ }
308
+ }
309
+ },
310
+ {
311
+ "_id": "510419a46dbc545f6f00000f",
312
+ "key": {
313
+ "date_from": {
314
+ "y": 2011,
315
+ "m": 9
316
+ },
317
+ "product": "HOTEL",
318
+ "contract": "test",
319
+ "status": "cancel_confirmed",
320
+ "provider": "MIKI",
321
+ "currency": "EUR",
322
+ "tlc": "YYY"
323
+ },
324
+ "value": {
325
+ "count": 2,
326
+ "price": {
327
+ "type": "NETNET",
328
+ "value": 0
329
+ }
330
+ }
331
+ },
332
+ {
333
+ "_id": "510419a46dbc545f6f000010",
334
+ "key": {
335
+ "date_from": {
336
+ "y": 2011,
337
+ "m": 10
338
+ },
339
+ "product": "HOTEL",
340
+ "contract": "test",
341
+ "status": "cancel_confirmed",
342
+ "provider": "OHG",
343
+ "currency": "EUR",
344
+ "tlc": "YYY"
345
+ },
346
+ "value": {
347
+ "count": 1,
348
+ "price": {
349
+ "type": "NETNET",
350
+ "value": 0
351
+ }
352
+ }
353
+ },
354
+ {
355
+ "_id": "510419a46dbc545f6f000011",
356
+ "key": {
357
+ "date_from": {
358
+ "y": 2011,
359
+ "m": 10
360
+ },
361
+ "product": "HOTEL",
362
+ "contract": "test.testconso",
363
+ "status": "cancel_confirmed",
364
+ "provider": "HOTELBEDS",
365
+ "currency": "EUR",
366
+ "tlc": "YYY"
367
+ },
368
+ "value": {
369
+ "count": 1,
370
+ "price": {
371
+ "type": "NETNET",
372
+ "value": 0
373
+ }
374
+ }
375
+ },
376
+ {
377
+ "_id": "510419a46dbc545f6f000012",
378
+ "key": {
379
+ "date_from": {
380
+ "y": 2011,
381
+ "m": 10
382
+ },
383
+ "product": "HOTEL",
384
+ "contract": "test",
385
+ "status": "book_confirmed",
386
+ "provider": "GTA",
387
+ "currency": "EUR",
388
+ "tlc": "YYY"
389
+ },
390
+ "value": {
391
+ "count": 3,
392
+ "price": {
393
+ "type": "NETNET",
394
+ "value": 1404
395
+ }
396
+ }
397
+ },
398
+ {
399
+ "_id": "510419a46dbc545f6f000013",
400
+ "key": {
401
+ "date_from": {
402
+ "y": 2011,
403
+ "m": 9
404
+ },
405
+ "product": "HOTEL",
406
+ "contract": "test",
407
+ "status": "cancel_confirmed",
408
+ "provider": "AOT",
409
+ "currency": "AUD",
410
+ "tlc": "YYY"
411
+ },
412
+ "value": {
413
+ "count": 9,
414
+ "price": {
415
+ "type": "NETNET",
416
+ "value": 0
417
+ }
418
+ }
419
+ },
420
+ {
421
+ "_id": "510419a46dbc545f6f000014",
422
+ "key": {
423
+ "date_from": {
424
+ "y": 2011,
425
+ "m": 9
426
+ },
427
+ "product": "HOTEL",
428
+ "contract": "test",
429
+ "status": "book_confirmed",
430
+ "provider": "AOT",
431
+ "currency": "AUD",
432
+ "tlc": "YYY"
433
+ },
434
+ "value": {
435
+ "count": 1,
436
+ "price": {
437
+ "type": "NETNET",
438
+ "value": 0
439
+ }
440
+ }
441
+ }
442
+ ]
@@ -0,0 +1,14 @@
1
+ [
2
+ { "_level": 1, "provider": "HOTELBEDS", "currency": "EUR", "date": "2013-01", "count": 3, "value": 30.0 },
3
+ { "_level": 2, "provider": "HOTELBEDS", "currency": "EUR", "date": "2013-01", "country": "IT", "count": 2, "value": 20.0 },
4
+ { "_level": 3, "provider": "HOTELBEDS", "currency": "EUR", "date": "2013-01", "country": "IT", "tlc": "ROM", "count": 1, "value": 10.0 },
5
+ { "_level": 3, "provider": "HOTELBEDS", "currency": "EUR", "date": "2013-01", "country": "IT", "tlc": "VCE", "count": 1, "value": 10.0 },
6
+ { "_level": 2, "provider": "HOTELBEDS", "currency": "EUR", "date": "2013-01", "country": "ES", "count": 1, "value": 10.0 },
7
+ { "_level": 3, "provider": "HOTELBEDS", "currency": "EUR", "date": "2013-01", "country": "ES", "tlc": "MAD", "count": 1, "value": 10.0 },
8
+ { "_level": 1, "provider": "HOTELBEDS", "currency": "EUR", "date": "2012-12", "count": 1, "value": 10.0 },
9
+ { "_level": 2, "provider": "HOTELBEDS", "currency": "EUR", "date": "2012-12", "country": "ES", "count": 1, "value": 10.0 },
10
+ { "_level": 3, "provider": "HOTELBEDS", "currency": "EUR", "date": "2012-12", "country": "ES", "tlc": "MAD", "count": 1, "value": 10.0 },
11
+ { "_level": 1, "provider": "GTA", "currency": "EUR", "date": "2012-12", "count": 1, "value": 10.0 },
12
+ { "_level": 2, "provider": "GTA", "currency": "EUR", "date": "2012-12", "country": "IT", "count": 1, "value": 10.0 },
13
+ { "_level": 3, "provider": "GTA", "currency": "EUR", "date": "2012-12", "country": "IT", "tlc": "ROM", "count": 1, "value": 10.0 }
14
+ ]
@@ -0,0 +1,17 @@
1
+ Feature: pivot tables
2
+
3
+ Scenario: simple
4
+ Given the json
5
+ """
6
+ [
7
+ ["c1", "r1", "v1"],
8
+ ["c1", "r2", "v2"],
9
+ ["c2", "r1", "v3"],
10
+ ["c2", "r2", "v4"]
11
+ ]
12
+ """
13
+ When I pivot it
14
+ Then the result table is
15
+ | group_by | c1 | c2 |
16
+ | r1 | v1 | v3 |
17
+ | r2 | v2 | v4 |
@@ -0,0 +1,16 @@
1
+ Feature: pivot projection
2
+
3
+ Scenario: magic
4
+ Given I load example2
5
+ When I magic-pivot it2
6
+ Then the result table is
7
+ | group_by | 2012-12 | 2013-01 |
8
+ | {"_level"=>1, "provider"=>"HOTELBEDS", "currency"=>"EUR"} | {"count"=>1, "value"=>10.0} | {"count"=>3, "value"=>30.0} |
9
+ | {"_level"=>2, "provider"=>"HOTELBEDS", "currency"=>"EUR", "country"=>"IT"} | | {"count"=>2, "value"=>20.0} |
10
+ | {"_level"=>3, "provider"=>"HOTELBEDS", "currency"=>"EUR", "country"=>"IT", "tlc"=>"ROM"} | | {"count"=>1, "value"=>10.0} |
11
+ | {"_level"=>3, "provider"=>"HOTELBEDS", "currency"=>"EUR", "country"=>"IT", "tlc"=>"VCE"} | | {"count"=>1, "value"=>10.0} |
12
+ | {"_level"=>2, "provider"=>"HOTELBEDS", "currency"=>"EUR", "country"=>"ES"} | {"count"=>1, "value"=>10.0} | {"count"=>1, "value"=>10.0} |
13
+ | {"_level"=>3, "provider"=>"HOTELBEDS", "currency"=>"EUR", "country"=>"ES", "tlc"=>"MAD"} | {"count"=>1, "value"=>10.0} | {"count"=>1, "value"=>10.0} |
14
+ | {"_level"=>1, "provider"=>"GTA", "currency"=>"EUR"} | {"count"=>1, "value"=>10.0} | |
15
+ | {"_level"=>2, "provider"=>"GTA", "currency"=>"EUR", "country"=>"IT"} | {"count"=>1, "value"=>10.0} | |
16
+ | {"_level"=>3, "provider"=>"GTA", "currency"=>"EUR", "country"=>"IT", "tlc"=>"ROM"} | {"count"=>1, "value"=>10.0} | |
@@ -0,0 +1,16 @@
1
+ Feature: pivot projection
2
+
3
+ Scenario: magic
4
+ Given I load example
5
+ When I magic-pivot it
6
+ Then the result table is
7
+ | group_by | 2011-07 | 2011-08 | 2011-09 | 2011-10 |
8
+ | HOTEL A34, GRO | 1 | | | |
9
+ | HOTELBEDS, YYY | | 1 | 3 | 1 |
10
+ | MIKI, YYY | | 1 | 2 | |
11
+ | KUONI, YYY | | 1 | 1 | |
12
+ | ROOMZ, YYY | | | | 1 |
13
+ | TOURICO, YYY | | | | 1 |
14
+ | AOT, YYY | | | 1 | 2 |
15
+ | OHG, YYY | | | | 1 |
16
+ | GTA, YYY | | | | 3 |
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe Reportability do
4
+ let(:input) do
5
+ [{"key"=>{"date_booked"=>{"y"=>2012, "m"=>8}, "provider"=>"REZROOMZ", "tlc"=>"MUC"}, "count"=>1}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>11}, "provider"=>"EUROTOURS", "tlc"=>"INN"}, "count"=>5}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>8}, "provider"=>"GTA", "tlc"=>"LON"}, "count"=>1}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>8}, "provider"=>"HOTELBEDS", "tlc"=>"BER"}, "count"=>4}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>8}, "provider"=>"HOTELBEDS", "tlc"=>"HAM"}, "count"=>2}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>8}, "provider"=>"MIKI", "tlc"=>"BER"}, "count"=>1}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>8}, "provider"=>"REZROOMZ", "tlc"=>"BER"}, "count"=>25}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>8}, "provider"=>"GTA", "tlc"=>"MEX"}, "count"=>1}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>8}, "provider"=>"TOURICO", "tlc"=>"BER"}, "count"=>1}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>10}, "provider"=>"WOTRA", "tlc"=>"BZO"}, "count"=>1}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>12}, "provider"=>"WOTRA", "tlc"=>"BUD"}, "count"=>1}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>8}, "provider"=>"GTA", "tlc"=>"BER"}, "count"=>8}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>12}, "provider"=>"GTA", "tlc"=>"WRO"}, "count"=>2}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>10}, "provider"=>"REZROOMZ", "tlc"=>"BER"}, "count"=>4}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>8}, "provider"=>"REZROOMZ", "tlc"=>"ESS"}, "count"=>1}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>11}, "provider"=>"WOTRA", "tlc"=>"MUN"}, "count"=>1}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>9}, "provider"=>"GTA", "tlc"=>"WRO"}, "count"=>3}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>11}, "provider"=>"WOTRA", "tlc"=>"BZO"}, "count"=>51}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>8}, "provider"=>"HOTELBEDS", "tlc"=>"MUC"}, "count"=>1}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>8}, "provider"=>"REZROOMZ", "tlc"=>"LON"}, "count"=>1}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>10}, "provider"=>"REZROOMZ", "tlc"=>"WRO"}, "count"=>6}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>8}, "provider"=>"REZROOMZ", "tlc"=>"MGL"}, "count"=>1}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>8}, "provider"=>"KUONI", "tlc"=>"RSE"}, "count"=>6}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>8}, "provider"=>"GTA", "tlc"=>"BKK"}, "count"=>2}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>12}, "provider"=>"WOTRA", "tlc"=>"VIE"}, "count"=>1}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>9}, "provider"=>"JACTRAVEL", "tlc"=>"BER"}, "count"=>1}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>8}, "provider"=>"KUONI", "tlc"=>"BER"}, "count"=>1}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>8}, "provider"=>"REZROOMZ", "tlc"=>"WRO"}, "count"=>1}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>11}, "provider"=>"WOTRA", "tlc"=>"LAX"}, "count"=>6}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>10}, "provider"=>"GTA", "tlc"=>"WRO"}, "count"=>6}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>8}, "provider"=>"REZROOMZ", "tlc"=>"MEX"}, "count"=>1}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>9}, "provider"=>"REZROOMZ", "tlc"=>"LON"}, "count"=>1}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>12}, "provider"=>"WOTRA", "tlc"=>"VIC"}, "count"=>1}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>8}, "provider"=>"GTA", "tlc"=>"HAM"}, "count"=>1}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>12}, "provider"=>"REZROOMZ", "tlc"=>"WRO"}, "count"=>2}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>8}, "provider"=>"JACTRAVEL", "tlc"=>"BER"}, "count"=>2}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>8}, "provider"=>"REZROOMZ", "tlc"=>"BKK"}, "count"=>2}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>12}, "provider"=>"GTA", "tlc"=>"BER"}, "count"=>1}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>9}, "provider"=>"REZROOMZ", "tlc"=>"BER"}, "count"=>20}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>10}, "provider"=>"HOTELBEDS", "tlc"=>"BER"}, "count"=>4}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>10}, "provider"=>"WOTRA", "tlc"=>"MUN"}, "count"=>71}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>9}, "provider"=>"KUONI", "tlc"=>"BER"}, "count"=>2}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>9}, "provider"=>"KUONI", "tlc"=>"LON"}, "count"=>1}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>8}, "provider"=>"HOTELBEDS", "tlc"=>"MGL"}, "count"=>1}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>12}, "provider"=>"WOTRA", "tlc"=>"LON"}, "count"=>1}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>9}, "provider"=>"HOTELBEDS", "tlc"=>"BER"}, "count"=>8}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>12}, "provider"=>"WOTRA", "tlc"=>"PRG"}, "count"=>1}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>8}, "provider"=>"REZROOMZ", "tlc"=>"HAM"}, "count"=>3}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>9}, "provider"=>"REZROOMZ", "tlc"=>"WRO"}, "count"=>3}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>12}, "provider"=>"WOTRA", "tlc"=>"INN"}, "count"=>2}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>12}, "provider"=>"WOTRA", "tlc"=>"WRO"}, "count"=>1}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>12}, "provider"=>"WOTRA", "tlc"=>"BZO"}, "count"=>1}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>9}, "provider"=>"GTA", "tlc"=>"BER"}, "count"=>9}, {"key"=>{"date_booked"=>{"y"=>2012, "m"=>8}, "provider"=>"GTA", "tlc"=>"WRO"}, "count"=>1}]
6
+ end
7
+
8
+ it 'just works' do
9
+ r = Reportability::Pivot.new
10
+ r.project do |row|
11
+ key = row['key']
12
+ [
13
+ "%4d-%02d" % [key['date_booked']['y'], key['date_booked']['m']],
14
+ [key['provider'], key['tlc']],
15
+ row['count']
16
+ ]
17
+ end
18
+ t = r.call [:date_booked, :provider_tlc, :count], input
19
+ t.cols.should == ['group_by', "2012-08", "2012-09", "2012-10", "2012-11", "2012-12"]
20
+ t.rows.should == [['group_by', "2012-08", "2012-09", "2012-10", "2012-11", "2012-12"], [["REZROOMZ", "MUC"], 1, nil, nil, nil, nil], [["EUROTOURS", "INN"], nil, nil, nil, 5, nil], [["GTA", "LON"], 1, nil, nil, nil, nil], [["HOTELBEDS", "BER"], 4, 8, 4, nil, nil], [["HOTELBEDS", "HAM"], 2, nil, nil, nil, nil], [["MIKI", "BER"], 1, nil, nil, nil, nil], [["REZROOMZ", "BER"], 25, 20, 4, nil, nil], [["GTA", "MEX"], 1, nil, nil, nil, nil], [["TOURICO", "BER"], 1, nil, nil, nil, nil], [["WOTRA", "BZO"], nil, nil, 1, 51, 1], [["WOTRA", "BUD"], nil, nil, nil, nil, 1], [["GTA", "BER"], 8, 9, nil, nil, 1], [["GTA", "WRO"], 1, 3, 6, nil, 2], [["REZROOMZ", "ESS"], 1, nil, nil, nil, nil], [["WOTRA", "MUN"], nil, nil, 71, 1, nil], [["HOTELBEDS", "MUC"], 1, nil, nil, nil, nil], [["REZROOMZ", "LON"], 1, 1, nil, nil, nil], [["REZROOMZ", "WRO"], 1, 3, 6, nil, 2], [["REZROOMZ", "MGL"], 1, nil, nil, nil, nil], [["KUONI", "RSE"], 6, nil, nil, nil, nil], [["GTA", "BKK"], 2, nil, nil, nil, nil], [["WOTRA", "VIE"], nil, nil, nil, nil, 1], [["JACTRAVEL", "BER"], 2, 1, nil, nil, nil], [["KUONI", "BER"], 1, 2, nil, nil, nil], [["WOTRA", "LAX"], nil, nil, nil, 6, nil], [["REZROOMZ", "MEX"], 1, nil, nil, nil, nil], [["WOTRA", "VIC"], nil, nil, nil, nil, 1], [["GTA", "HAM"], 1, nil, nil, nil, nil], [["REZROOMZ", "BKK"], 2, nil, nil, nil, nil], [["KUONI", "LON"], nil, 1, nil, nil, nil], [["HOTELBEDS", "MGL"], 1, nil, nil, nil, nil], [["WOTRA", "LON"], nil, nil, nil, nil, 1], [["WOTRA", "PRG"], nil, nil, nil, nil, 1], [["REZROOMZ", "HAM"], 3, nil, nil, nil, nil], [["WOTRA", "INN"], nil, nil, nil, nil, 2], [["WOTRA", "WRO"], nil, nil, nil, nil, 1]]
21
+ end
22
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+ require 'summary'
3
+
4
+ describe Reportability::Summary do
5
+ it "description" do
6
+ summary = Reportability::Summary.new(hierarchy=[:provider, :country, :tlc], always=[:currency, :date], values=[:count, :value])
7
+ rows = [{provider: 'HOTELBEDS', country: 'IT', tlc: 'ROM', currency: 'EUR', date: '2013-01', count: 1, value: 10.0},
8
+ {provider: 'HOTELBEDS', country: 'IT', tlc: 'VCE', currency: 'EUR', date: '2013-01', count: 1, value: 10.0},
9
+ {provider: 'HOTELBEDS', country: 'ES', tlc: 'MAD', currency: 'EUR', date: '2013-01', count: 1, value: 10.0},
10
+ {provider: 'HOTELBEDS', country: 'ES', tlc: 'MAD', currency: 'EUR', date: '2012-12', count: 1, value: 10.0},
11
+ {provider: 'GTA', country: 'IT', tlc: 'ROM', currency: 'EUR', date: '2012-12', count: 1, value: 10.0}]
12
+
13
+ rows.each do |row|
14
+ summary.push(row)
15
+ end
16
+
17
+ expected = [
18
+ { _level: 1, provider: 'HOTELBEDS', currency: 'EUR', date: '2013-01', count: 3, value: 30.0 },
19
+ { _level: 2, provider: 'HOTELBEDS', currency: 'EUR', date: '2013-01', country: 'IT', count: 2, value: 20.0 },
20
+ { _level: 3, provider: 'HOTELBEDS', currency: 'EUR', date: '2013-01', country: 'IT', tlc: 'ROM', count: 1, value: 10.0 },
21
+ { _level: 3, provider: 'HOTELBEDS', currency: 'EUR', date: '2013-01', country: 'IT', tlc: 'VCE', count: 1, value: 10.0 },
22
+ { _level: 2, provider: 'HOTELBEDS', currency: 'EUR', date: '2013-01', country: 'ES', count: 1, value: 10.0 },
23
+ { _level: 3, provider: 'HOTELBEDS', currency: 'EUR', date: '2013-01', country: 'ES', tlc: 'MAD', count: 1, value: 10.0 },
24
+ { _level: 1, provider: 'HOTELBEDS', currency: 'EUR', date: '2012-12', count: 1, value: 10.0 },
25
+ { _level: 2, provider: 'HOTELBEDS', currency: 'EUR', date: '2012-12', country: 'ES', count: 1, value: 10.0 },
26
+ { _level: 3, provider: 'HOTELBEDS', currency: 'EUR', date: '2012-12', country: 'ES', tlc: 'MAD', count: 1, value: 10.0 },
27
+ { _level: 1, provider: 'GTA', currency: 'EUR', date: '2012-12', count: 1, value: 10.0 },
28
+ { _level: 2, provider: 'GTA', currency: 'EUR', date: '2012-12', country: 'IT', count: 1, value: 10.0 },
29
+ { _level: 3, provider: 'GTA', currency: 'EUR', date: '2012-12', country: 'IT', tlc: 'ROM', count: 1, value: 10.0 }
30
+ ]
31
+ summary.summary.should == expected
32
+ end
33
+ end
34
+
35
+
@@ -0,0 +1,30 @@
1
+ Feature: Summary
2
+
3
+ Scenario: Sunny Day
4
+
5
+ Given the input table
6
+ | provider | country | tlc | currency | date | count | value |
7
+ | HOTELBEDS | IT | ROM | EUR | 2013-01 | 1 | 10 |
8
+ | HOTELBEDS | IT | VCE | EUR | 2013-01 | 1 | 10 |
9
+ | HOTELBEDS | ES | MAD | EUR | 2013-01 | 1 | 10 |
10
+ | GTA | IT | ROM | EUR | 2013-01 | 1 | 10 |
11
+ And the fields
12
+ | field | type |
13
+ | provider | group:1 |
14
+ | country | group:2 |
15
+ | tlc | group:3 |
16
+ | currency | |
17
+ | date | |
18
+ | count | sum |
19
+ | value | sum |
20
+ Then the summary is
21
+ | group_level | provider | country | tlc | currency | date | count | value |
22
+ | 1 | HOTELBEDS | | | EUR | 2013-01 | 3 | 30 |
23
+ | 2 | HOTELBEDS | IT | | EUR | 2013-01 | 2 | 20 |
24
+ | 3 | HOTELBEDS | IT | ROM | EUR | 2013-01 | 1 | 10 |
25
+ | 3 | HOTELBEDS | IT | VCE | EUR | 2013-01 | 1 | 10 |
26
+ | 2 | HOTELBEDS | ES | | EUR | 2013-01 | 1 | 10 |
27
+ | 3 | HOTELBEDS | ES | MAD | EUR | 2013-01 | 1 | 10 |
28
+ | 1 | GTA | | | EUR | 2013-01 | 1 | 10 |
29
+ | 2 | GTA | IT | | EUR | 2013-01 | 1 | 10 |
30
+ | 3 | GTA | IT | ROM | EUR | 2013-01 | 1 | 10 |
data/spec/spec.rake ADDED
@@ -0,0 +1,25 @@
1
+ require 'rspec/core/rake_task'
2
+
3
+ SPEC_SUITES = [
4
+ { :id => :unit,
5
+ :title => 'unit',
6
+ :files => %w(spec/lib/**/*_spec.rb spec/lib/**/*.feature) },
7
+ { :id => :acceptance,
8
+ :title => 'acceptance',
9
+ :files => %w(spec/acceptance/**/*.feature spec/acceptance/**/*_spec.rb),
10
+ :opts => '-I spec/acceptance -r ./spec/acceptance/acceptance_helper.rb' },
11
+ ]
12
+
13
+
14
+ namespace :spec do
15
+ SPEC_SUITES.each do |suite|
16
+ desc "Run #{suite[:title]} tests"
17
+ RSpec::Core::RakeTask.new(suite[:id]) do |t|
18
+ spec_files = []
19
+ suite[:files].each { |glob| spec_files += Dir[glob] } if suite[:files]
20
+ t.pattern = spec_files
21
+
22
+ t.rspec_opts = suite[:opts] if suite.has_key? :opts
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,8 @@
1
+ require 'bundler/setup'
2
+ require 'turnip/rspec'
3
+ require 'reportability'
4
+
5
+ Dir.glob("spec/lib/**/*_steps.rb") { |f| load f, true }
6
+
7
+ $LOAD_PATH << File.expand_path('../../lib', __FILE__) # the gem's lib dir
8
+ $LOAD_PATH << File.expand_path('../../lib/reportability', __FILE__) # the gem's lib dir
metadata ADDED
@@ -0,0 +1,246 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: reportability
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Piotr Zolnierek
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-04-20 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: multi_json
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: active_support
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: 2.9.0
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: 2.9.0
62
+ - !ruby/object:Gem::Dependency
63
+ name: turnip
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: guard
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: guard-rspec
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: guard-bundler
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: growl
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ - !ruby/object:Gem::Dependency
143
+ name: rake
144
+ requirement: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ! '>='
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ type: :development
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ - !ruby/object:Gem::Dependency
159
+ name: rb-fsevent
160
+ requirement: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ~>
164
+ - !ruby/object:Gem::Version
165
+ version: 0.9.1
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ~>
172
+ - !ruby/object:Gem::Version
173
+ version: 0.9.1
174
+ description: Reportbility
175
+ email:
176
+ - pz@anixe.pl
177
+ executables: []
178
+ extensions: []
179
+ extra_rdoc_files: []
180
+ files:
181
+ - .gitignore
182
+ - .rspec
183
+ - CHANGELOG.md
184
+ - Gemfile
185
+ - Guardfile
186
+ - LICENSE.txt
187
+ - README.md
188
+ - Rakefile
189
+ - lib/reportability.rb
190
+ - lib/reportability/pivot.rb
191
+ - lib/reportability/summary.rb
192
+ - lib/reportability/version.rb
193
+ - reportability.gemspec
194
+ - spec/lib/basic_steps.rb
195
+ - spec/lib/example.json
196
+ - spec/lib/example2.json
197
+ - spec/lib/pivot.feature
198
+ - spec/lib/pivot2.feature
199
+ - spec/lib/pivot_project.feature
200
+ - spec/lib/pivot_spec.rb
201
+ - spec/lib/reportability/summary_spec.rb
202
+ - spec/lib/summary.feature
203
+ - spec/spec.rake
204
+ - spec/spec_helper.rb
205
+ homepage: http://github.com/pzol/reportability
206
+ licenses: []
207
+ post_install_message:
208
+ rdoc_options: []
209
+ require_paths:
210
+ - lib
211
+ required_ruby_version: !ruby/object:Gem::Requirement
212
+ none: false
213
+ requirements:
214
+ - - ! '>='
215
+ - !ruby/object:Gem::Version
216
+ version: '0'
217
+ segments:
218
+ - 0
219
+ hash: 1465791747348344622
220
+ required_rubygems_version: !ruby/object:Gem::Requirement
221
+ none: false
222
+ requirements:
223
+ - - ! '>='
224
+ - !ruby/object:Gem::Version
225
+ version: '0'
226
+ segments:
227
+ - 0
228
+ hash: 1465791747348344622
229
+ requirements: []
230
+ rubyforge_project:
231
+ rubygems_version: 1.8.23
232
+ signing_key:
233
+ specification_version: 3
234
+ summary: Helps with reports
235
+ test_files:
236
+ - spec/lib/basic_steps.rb
237
+ - spec/lib/example.json
238
+ - spec/lib/example2.json
239
+ - spec/lib/pivot.feature
240
+ - spec/lib/pivot2.feature
241
+ - spec/lib/pivot_project.feature
242
+ - spec/lib/pivot_spec.rb
243
+ - spec/lib/reportability/summary_spec.rb
244
+ - spec/lib/summary.feature
245
+ - spec/spec.rake
246
+ - spec/spec_helper.rb