rflare 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (7) hide show
  1. checksums.yaml +7 -0
  2. data/.gemtest +0 -0
  3. data/Rakefile +8 -0
  4. data/bin/rflare +59 -0
  5. data/lib/rflare.rb +181 -0
  6. data/test/test_rflare.rb +290 -0
  7. metadata +79 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3d3aaf86caee415439c6b079238eb08f64f99361
4
+ data.tar.gz: 8577586e4feef9089da739591cc7ba6fe0ac13cf
5
+ SHA512:
6
+ metadata.gz: e322a3d7229063a594df73674c2fbb149fcc7a1b8a0a3041cdfcfc2511982ef9c91faf6d08b115949e3c958c069bd6c91cc7513f70a589a98e715c82d20f9197
7
+ data.tar.gz: eda58c277896406c7d880bc77684b412b19820c27448e8186d75281b280c967aff40faf0db1a74d084b8f4d7c09f3f9c80c566033e393082c41c69be75f4f474
File without changes
@@ -0,0 +1,8 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.libs << 'test'
5
+ end
6
+
7
+ desc "Run tests"
8
+ task :default => :test
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'csv'
4
+ require 'optparse'
5
+ require 'tgf'
6
+ require 'rflare'
7
+
8
+ csv_opts = {}
9
+ nodes, edges = [], []
10
+
11
+ OptionParser.new do |opts|
12
+ opts.banner = "Usage: rflare [options]"
13
+
14
+ opts.on("-F", "--field-separator [FS]") do |fs|
15
+ csv_opts[:col_sep] = fs
16
+ end
17
+
18
+ opts.on("-Q", "--quote-char [QC]") do |qc|
19
+ csv_opts[:quote_char] = qc
20
+ end
21
+
22
+ opts.on("-f", "--file [file]") do |file|
23
+ nodes, edges = TGF.parse(File(q))
24
+ end
25
+
26
+ opts.on("-e", "--evaluate [query]") do |query|
27
+ nodes, edges = TGF.parse(query, ';')
28
+ end
29
+ end.parse!
30
+
31
+ def rows_and_cols str
32
+ str.nil? ? [nil, nil] : str.split(/\s+/, 2)
33
+ end
34
+
35
+ out = CSV.new $stdout, csv_opts
36
+ ARGV.each do |csv_file|
37
+ ss = RFlare::Spreadsheet.new(CSV.read(csv_file, csv_opts))
38
+ my_nodes = nodes.map { |node|
39
+ if node.label.nil?
40
+ RFlare::Node.new node.id, nil, nil, nil, ss.row_bounds, ss.col_bounds
41
+ else
42
+ m = /^\/((?:.*\\\/)*.*)\/\s*(.+)?/.match node.label
43
+ rows, columns = rows_and_cols m[2]
44
+ RFlare::Node.new node.id, m[1], rows, columns, ss.row_bounds, ss.col_bounds
45
+ end
46
+ }
47
+ my_edges = edges.map { |edge|
48
+ rows, columns = rows_and_cols edge.label
49
+ RFlare::Edge.new edge.from, edge.to, rows, columns
50
+ }
51
+ root = my_nodes[0]
52
+
53
+ RFlare::Results.new(my_edges, my_nodes, ss, root).each { |match|
54
+ n = my_nodes.select {|node| node.id[0] != '_'}
55
+ out << n.map {|node| match[node.id] || ''}
56
+ }
57
+ end
58
+ out.flush
59
+
@@ -0,0 +1,181 @@
1
+
2
+ class Array
3
+ def bounds; 0 ... size; end
4
+ end
5
+
6
+ class Range
7
+ def cap num
8
+ num < min ? min : (num > max ? max : num)
9
+ end
10
+ end
11
+
12
+ module RFlare
13
+
14
+ class Square
15
+ def initialize rows, columns
16
+ @rows, @columns = rows, columns
17
+ end
18
+
19
+ attr_reader :rows, :columns
20
+ include Enumerable
21
+
22
+ def each
23
+ @rows.each {|row|
24
+ @columns.each {|col|
25
+ yield row, col
26
+ }
27
+ }
28
+ end
29
+
30
+ def include? row, col
31
+ @rows.include? row and @columns.include? col
32
+ end
33
+
34
+ def == other
35
+ @rows == other.rows and @columns == other.columns
36
+ end
37
+ end
38
+
39
+ class Node
40
+ def initialize id, match, rows, columns, row_bounds, col_bounds
41
+ @id = id || '_'
42
+ @match = Regexp.new(match || '.*')
43
+ @valid = Square.new(
44
+ Spec.new(rows || '0:*').range(0, row_bounds),
45
+ Spec.new(columns || '0:*').range(0, col_bounds))
46
+ end
47
+
48
+ attr_reader :id, :match, :valid
49
+
50
+ def matches ss, row, col
51
+ @valid.include? row, col and (ss[row,col] || '').to_s =~ @match
52
+ end
53
+ end
54
+
55
+ class Spec
56
+ def initialize spec
57
+ @spec = spec.to_s
58
+ raise "invalid spec '#{@spec}'" if @spec !~ /[+-]?([0-9]+|\*)(:([+-]?([0-9]+|\*))?)?/
59
+ end
60
+
61
+ # + or - means relative to num, otherwise absolute
62
+ def range num, bounds
63
+ bits = @spec.split ":", 2
64
+ s = bits.size == 1 ? @spec : bits[0]
65
+ e = bits.size == 1 ? @spec : bits[1]
66
+ range_start(num, bounds, s) .. range_end(num, bounds, e)
67
+ end
68
+
69
+ private
70
+
71
+ def range_start num, bounds, spec
72
+ if spec == '+*' or spec == '*'
73
+ num + 1
74
+ elsif spec == '-*'
75
+ bounds.min
76
+ elsif spec[0] == '+' or spec[0] == '-'
77
+ offset = spec[1, spec.length - 1].to_i
78
+ spec[0] == '+' ? (num + offset) : (num - offset)
79
+ elsif spec == ''
80
+ bounds.min
81
+ else
82
+ spec.to_i
83
+ end
84
+ end
85
+
86
+ def range_end num, bounds, spec
87
+ if spec == '+*' or spec == '*' or spec == ""
88
+ bounds.max
89
+ elsif spec == '-*'
90
+ num - 1
91
+ elsif spec[0] == '+' or spec[0] == '-'
92
+ offset = spec[1, spec.length - 1].to_i
93
+ spec[0] == '+' ? (num + offset) : (num - offset)
94
+ else
95
+ spec.to_i
96
+ end
97
+ end
98
+ end
99
+
100
+ class Edge
101
+ def initialize from, to, vert, horiz
102
+ @from, @to = from, to
103
+ @vert = Spec.new(vert || '+0')
104
+ @horiz = Spec.new(horiz || '+0')
105
+ end
106
+
107
+ attr_reader :from, :to
108
+
109
+ def get_square row, col, row_bounds, col_bounds
110
+ Square.new(
111
+ @vert.range(row, row_bounds),
112
+ @horiz.range(col, col_bounds))
113
+ end
114
+ end
115
+
116
+ class Spreadsheet
117
+ def initialize arr_of_rows
118
+ @data = arr_of_rows
119
+ @row_bounds = @data.bounds
120
+ @col_bounds = @data.empty? ? (0...0) : @data[0].bounds
121
+ end
122
+
123
+ def [] row, col
124
+ if @row_bounds.include? row and @col_bounds.include? col
125
+ @data[row][col]
126
+ else
127
+ nil
128
+ end
129
+ end
130
+
131
+ attr_reader :row_bounds, :col_bounds
132
+ end
133
+
134
+ class Results
135
+ def initialize edges, nodes, ss, root
136
+ @ss, @root = ss, root
137
+ @edges_byfrom = Hash.new {|h,k| h[k] = [] }
138
+ edges.each {|edge| @edges_byfrom[edge.from] << edge }
139
+ @nodes_byid = Hash.new
140
+ nodes.each {|node| @nodes_byid[node.id] = node}
141
+ end
142
+
143
+ include Enumerable
144
+
145
+ # start at root, looking for trees
146
+ def each
147
+ @root.valid.each {|row, col|
148
+ matches(row, col, @root).each { |match| yield match }
149
+ }
150
+ end
151
+
152
+ private
153
+
154
+ def matches row, col, node
155
+ return [] if !node.matches(@ss, row, col)
156
+
157
+ me = {node.id => @ss[row,col]}
158
+ edges = @edges_byfrom[node.id]
159
+ return [me] if edges.empty?
160
+
161
+ # get array with dims:
162
+ # (1) each edge from this
163
+ # -- we flatten the square-for-each-edge dim
164
+ # (2) each match (a Hash) from edge
165
+ edge_matches = edges.map do |edge|
166
+ to = @nodes_byid[edge.to]
167
+ sq = edge.get_square(row, col, @ss.row_bounds, @ss.col_bounds)
168
+ paths = sq.flat_map do |sq_row, sq_col|
169
+ matches sq_row, sq_col, to
170
+ end
171
+ paths.select {|a| !a.empty?}
172
+ end
173
+
174
+ [me].product(*edge_matches).map do |assignments_arr|
175
+ assignments_arr.inject Hash.new, :merge
176
+ end
177
+ end
178
+
179
+ end
180
+ end
181
+
@@ -0,0 +1,290 @@
1
+ require 'minitest/autorun'
2
+ require 'rflare'
3
+
4
+ class Hash
5
+ def <=> other
6
+ k = keys.sort <=> other.keys.sort
7
+ return k if k != 0
8
+ keys.sort.each {|key|
9
+ k = self[key] <=> other[key]
10
+ return k if k != 0
11
+ }
12
+ 0
13
+ end
14
+ end
15
+
16
+ class FlashRangeTest < Minitest::Test
17
+ def test_in
18
+ assert_equal 4, (2..5).cap(4)
19
+ end
20
+
21
+ def test_after
22
+ assert_equal 5, (2..5).cap(7)
23
+ end
24
+
25
+ def test_before
26
+ assert_equal 2, (2..5).cap(1)
27
+ end
28
+ end
29
+
30
+ class FlashSquareTest < Minitest::Test
31
+ def test_include_in
32
+ assert RFlare::Square.new(2..4, 3..5).include? 3, 4
33
+ end
34
+
35
+ def test_include_out
36
+ refute RFlare::Square.new(2..4, 3..5).include? 1, 4
37
+ end
38
+
39
+ def test_enumerate
40
+ assert_equal [[2,3], [2,4], [2,5], [3,3], [3,4], [3,5]], RFlare::Square.new(2..3, 3..5).to_a
41
+ end
42
+
43
+ def test_equals
44
+ assert_equal RFlare::Square.new(2..3, 4..5), RFlare::Square.new(2..3, 4..5)
45
+ end
46
+ end
47
+
48
+ class FlashSpecTest < Minitest::Test
49
+ def setup
50
+ @bounds = 0..10
51
+ end
52
+
53
+ def test_single_relativeconst
54
+ assert_equal (4..4), RFlare::Spec.new('+1').range(3, @bounds)
55
+ end
56
+
57
+ def test_single_plusstar
58
+ assert_equal (4..@bounds.max), RFlare::Spec.new('+*').range(3, @bounds)
59
+ end
60
+
61
+ def test_single_plusstar2
62
+ assert_equal (4..@bounds.max), RFlare::Spec.new('*').range(3, @bounds)
63
+ end
64
+
65
+ def test_minusone
66
+ assert_equal (2..2), RFlare::Spec.new('-1').range(3, @bounds)
67
+ end
68
+
69
+ def test_minusstar
70
+ assert_equal (@bounds.min..2), RFlare::Spec.new('-*').range(3, @bounds)
71
+ end
72
+
73
+ def test_abs
74
+ assert_equal (1..1), RFlare::Spec.new('1').range(3, @bounds)
75
+ end
76
+
77
+ def test_range_relativeconst
78
+ assert_equal (4..6), RFlare::Spec.new('+1:+3').range(3, @bounds)
79
+ end
80
+
81
+ def test_range_star
82
+ assert_equal (5..@bounds.max), RFlare::Spec.new('+2:+*').range(3, @bounds)
83
+ end
84
+
85
+ def test_invalid
86
+ assert_raises(RuntimeError) { RFlare::Spec.new 'hat' }
87
+ end
88
+
89
+ def test_range_blank_start
90
+ assert_equal (@bounds.min..4), RFlare::Spec.new(':4').range(3, @bounds)
91
+ end
92
+
93
+ def test_range_blank_end
94
+ assert_equal (1..@bounds.max), RFlare::Spec.new('1:').range(3, @bounds)
95
+ end
96
+
97
+ end
98
+
99
+ class FlashNodeTest < Minitest::Test
100
+ def setup
101
+ @ss = RFlare::Spreadsheet.new [[0,1,2],['a','b','c']]
102
+ end
103
+
104
+ def test_match
105
+ n = RFlare::Node.new nil, nil, 0, nil, @ss.row_bounds, @ss.col_bounds
106
+ assert_equal RFlare::Square.new(0..0, 0..2), n.valid
107
+ assert n.matches @ss, 0, 0
108
+ assert n.matches @ss, 0, 1
109
+ assert n.matches @ss, 0, 2
110
+ refute n.matches @ss, 1, 0
111
+ refute n.matches @ss, 1, 1
112
+ refute n.matches @ss, 1, 2
113
+ end
114
+ end
115
+
116
+ class FlashSpreadsheetTest < Minitest::Test
117
+ def test_empty
118
+ ss = RFlare::Spreadsheet.new []
119
+ assert_equal 0...0, ss.row_bounds
120
+ assert_equal 0...0, ss.col_bounds
121
+ assert_nil ss[0,0]
122
+ end
123
+
124
+ def test_full
125
+ ss = RFlare::Spreadsheet.new [[1,2,3],['a','b','c']]
126
+ assert_equal 0...2, ss.row_bounds
127
+ assert_equal 0...3, ss.col_bounds
128
+ assert_equal 1, ss[0,0]
129
+ assert_equal 'b', ss[1,1]
130
+ end
131
+ end
132
+
133
+ class FlashResultsTest < Minitest::Test
134
+ def setup
135
+ @ss = RFlare::Spreadsheet.new [
136
+ [ nil, 'value', 'year', 'value', 'year', 'Comments'],
137
+ [ 'Albania', 1000, 1950, 930, 1981, 'FRA 1'],
138
+ [ 'Austria', 3139, 1951, 3177, 1955, 'FRA 3'],
139
+ [ 'Belgium', 541, 1947, 601, 1950, nil ],
140
+ ['Bulgaria', 2964, 1947, 3259, 1958, 'FRA 1'],
141
+ [ 'Czech', 2416, 1950, 2503, 1960, 'NC']
142
+ ]
143
+ end
144
+
145
+ def node id, match, rows = nil, columns = nil
146
+ RFlare::Node.new id, match, rows, columns, @ss.row_bounds, @ss.col_bounds
147
+ end
148
+
149
+ def edge from, to, vert, horiz
150
+ RFlare::Edge.new from, to, vert, horiz
151
+ end
152
+
153
+ def assert_matches edges, nodes, expected
154
+ actual = RFlare::Results.new(edges, nodes, @ss, nodes[0]).to_a
155
+ assert_equal expected.sort, actual.sort
156
+ end
157
+
158
+ # the tests:
159
+
160
+ def test_simplecell
161
+ nodes = [node(3, '^value$')]
162
+ edges = []
163
+ expected = [{3 => 'value'}, {3 => 'value'}]
164
+ assert_matches edges, nodes, expected
165
+ end
166
+
167
+ def test_header
168
+ nodes = [node(3, '^value$', 0, nil)]
169
+ edges = []
170
+ expected = [{3 => 'value'}, {3 => 'value'}]
171
+ assert_matches edges, nodes, expected
172
+ end
173
+
174
+ def test_oneedge
175
+ nodes = [node(4,'^[0-9]+$'), node(3, '^value$')]
176
+ edges = [edge(4, 3, '-*', nil)]
177
+ expected = [
178
+ {3 => 'value', 4 => 1000},
179
+ {3 => 'value', 4 => 3139},
180
+ {3 => 'value', 4 => 541},
181
+ {3 => 'value', 4 => 2964},
182
+ {3 => 'value', 4 => 2416},
183
+ {3 => 'value', 4 => 930},
184
+ {3 => 'value', 4 => 3177},
185
+ {3 => 'value', 4 => 601},
186
+ {3 => 'value', 4 => 3259},
187
+ {3 => 'value', 4 => 2503}
188
+ ]
189
+ assert_matches edges, nodes, expected
190
+ end
191
+
192
+ def test_twoedges
193
+ nodes = [
194
+ node('v','^[0-9]+$'),
195
+ node('vcol', '^value$'),
196
+ node('y','^19[0-9]{2}$'),
197
+ ]
198
+ edges = [
199
+ edge('v', 'vcol', '-*', nil),
200
+ edge('v', 'y', nil, '+1')
201
+ ]
202
+ expected = [
203
+ {'vcol' => 'value', 'v' => 1000, 'y' => 1950},
204
+ {'vcol' => 'value', 'v' => 3139, 'y' => 1951},
205
+ {'vcol' => 'value', 'v' => 541, 'y' => 1947},
206
+ {'vcol' => 'value', 'v' => 2964, 'y' => 1947},
207
+ {'vcol' => 'value', 'v' => 2416, 'y' => 1950},
208
+ {'vcol' => 'value', 'v' => 930, 'y' => 1981},
209
+ {'vcol' => 'value', 'v' => 3177, 'y' => 1955},
210
+ {'vcol' => 'value', 'v' => 601, 'y' => 1950},
211
+ {'vcol' => 'value', 'v' => 3259, 'y' => 1958},
212
+ {'vcol' => 'value', 'v' => 2503, 'y' => 1960}
213
+ ]
214
+ assert_matches edges, nodes, expected
215
+ end
216
+
217
+ def test_twolevelrecursion
218
+ nodes = [
219
+ node('v','^[0-9]+$'),
220
+ node('vcol', '^value$'),
221
+ node('y','^19[0-9]{2}$'),
222
+ node('ycol', '^year$'),
223
+ ]
224
+ edges = [
225
+ edge('v', 'vcol', '-*', nil),
226
+ edge('y', 'ycol', '-*', nil),
227
+ edge('v', 'y', nil, '+1'),
228
+ ]
229
+ expected = [
230
+ {'vcol' => 'value', 'v' => 1000, 'y' => 1950, 'ycol' => 'year'},
231
+ {'vcol' => 'value', 'v' => 3139, 'y' => 1951, 'ycol' => 'year'},
232
+ {'vcol' => 'value', 'v' => 541, 'y' => 1947, 'ycol' => 'year'},
233
+ {'vcol' => 'value', 'v' => 2964, 'y' => 1947, 'ycol' => 'year'},
234
+ {'vcol' => 'value', 'v' => 2416, 'y' => 1950, 'ycol' => 'year'},
235
+ {'vcol' => 'value', 'v' => 930, 'y' => 1981, 'ycol' => 'year'},
236
+ {'vcol' => 'value', 'v' => 3177, 'y' => 1955, 'ycol' => 'year'},
237
+ {'vcol' => 'value', 'v' => 601, 'y' => 1950, 'ycol' => 'year'},
238
+ {'vcol' => 'value', 'v' => 3259, 'y' => 1958, 'ycol' => 'year'},
239
+ {'vcol' => 'value', 'v' => 2503, 'y' => 1960, 'ycol' => 'year'},
240
+ ]
241
+ assert_matches edges, nodes, expected
242
+ end
243
+
244
+ def test_withrowlimit
245
+ nodes = [node(3, '^[A-Za-z]+$', '1:*', 0)]
246
+ edges = []
247
+ expected = [
248
+ {3 => 'Albania'},
249
+ {3 => 'Austria'},
250
+ {3 => 'Belgium'},
251
+ {3 => 'Bulgaria'},
252
+ {3 => 'Czech'},
253
+ ]
254
+ assert_matches edges, nodes, expected
255
+ end
256
+
257
+ def test_frompaper
258
+ nodes = [
259
+ node('c', '^[A-Za-z]+$', '1:*', 0),
260
+ node('v','^[0-9]+$', '1:*', nil),
261
+ node('vcol', '^value$', 0, nil),
262
+ node('y','^19[0-9]{2}$', '1:*', nil),
263
+ node('ycol', '^year$', 0, nil),
264
+ node('m','^[A-Za-z 0-9]*$', '1:*', nil),
265
+ node('mcol', '^Comments$', 0, nil),
266
+ ]
267
+ edges = [
268
+ edge('v', 'vcol', '-*', nil),
269
+ edge('y', 'ycol', '-*', nil),
270
+ edge('m', 'mcol', '-*', nil),
271
+ edge('c', 'v', nil, '+*'),
272
+ edge('v', 'y', nil, '+1'),
273
+ edge('y', 'm', nil, '+*'),
274
+ ]
275
+ expected = [
276
+ {'vcol' => 'value', 'v' => 1000, 'y' => 1950, 'ycol' => 'year', 'c' => 'Albania', 'mcol' => 'Comments', 'm' => 'FRA 1'},
277
+ {'vcol' => 'value', 'v' => 3139, 'y' => 1951, 'ycol' => 'year', 'c' => 'Austria', 'mcol' => 'Comments', 'm' => 'FRA 3'},
278
+ {'vcol' => 'value', 'v' => 541, 'y' => 1947, 'ycol' => 'year', 'c' => 'Belgium', 'mcol' => 'Comments', 'm' => nil},
279
+ {'vcol' => 'value', 'v' => 2964, 'y' => 1947, 'ycol' => 'year', 'c' => 'Bulgaria', 'mcol' => 'Comments', 'm' => 'FRA 1'},
280
+ {'vcol' => 'value', 'v' => 2416, 'y' => 1950, 'ycol' => 'year', 'c' => 'Czech', 'mcol' => 'Comments', 'm' => 'NC'},
281
+ {'vcol' => 'value', 'v' => 930, 'y' => 1981, 'ycol' => 'year', 'c' => 'Albania', 'mcol' => 'Comments', 'm' => 'FRA 1'},
282
+ {'vcol' => 'value', 'v' => 3177, 'y' => 1955, 'ycol' => 'year', 'c' => 'Austria', 'mcol' => 'Comments', 'm' => 'FRA 3'},
283
+ {'vcol' => 'value', 'v' => 601, 'y' => 1950, 'ycol' => 'year', 'c' => 'Belgium', 'mcol' => 'Comments', 'm' => nil},
284
+ {'vcol' => 'value', 'v' => 3259, 'y' => 1958, 'ycol' => 'year', 'c' => 'Bulgaria', 'mcol' => 'Comments', 'm' => 'FRA 1'},
285
+ {'vcol' => 'value', 'v' => 2503, 'y' => 1960, 'ycol' => 'year', 'c' => 'Czech', 'mcol' => 'Comments', 'm' => 'NC'},
286
+ ]
287
+ assert_matches edges, nodes, expected
288
+ end
289
+ end
290
+
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rflare
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Remis
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: tgf
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10'
41
+ description: A command-line tool to extract relational data from semi-structured CSV
42
+ files
43
+ email: remis.thoughts@gmail.com
44
+ executables:
45
+ - rflare
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ".gemtest"
50
+ - Rakefile
51
+ - bin/rflare
52
+ - lib/rflare.rb
53
+ - test/test_rflare.rb
54
+ homepage: https://research.microsoft.com/pubs/214302/flashrelate-tech-report-April2014.pdf
55
+ licenses:
56
+ - Apache-2.0
57
+ metadata: {}
58
+ post_install_message:
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ requirements: []
73
+ rubyforge_project:
74
+ rubygems_version: 2.2.2
75
+ signing_key:
76
+ specification_version: 4
77
+ summary: Ruby version of Flare
78
+ test_files:
79
+ - test/test_rflare.rb