bmg 0.18.13 → 0.19.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0ceadf8947aa041841941225e88396cc37ff7319
4
- data.tar.gz: 9c695d3305101ff4a73bcdef5e3788648e9b2d27
3
+ metadata.gz: 5d3871be740059340140a52f8b47892ef64effee
4
+ data.tar.gz: 721d3073d321a0d5b6bc3a1a8426522e35cc7138
5
5
  SHA512:
6
- metadata.gz: 70db4550decd609934e1d8d643983766b5b50b9f0354b2405dfdc710b9580a885e4754c907ed5011856e905308af9647c029f0dd612657e72b45af0465eaced2
7
- data.tar.gz: 5ed5e7f6d1d9baa8070112a36229e8961e4b5a531acbdac808fcf1f5c008fc91ae3ceadc5c3b4c1d0ace22ca6f861074e79b6d957498740a8fba3d5e99875068
6
+ metadata.gz: 28e1cd068d476e15f0577f70d9e84ca74f2db6e4dc849945c6c94bcf280ad76cc160276d00705cb98a2a5c61db785352a805c3c76034251b1da41c5f511669d5
7
+ data.tar.gz: b36c7e59b259c5072a37b64f33b422c376794bca64ed02623f7124acd786c1e5f3792a9264ce6cc1f672c2dd281c34e806965a7f0a67bb585afd81a67b830caa
@@ -10,20 +10,18 @@ module Bmg
10
10
  }
11
11
 
12
12
  def initialize(type, path_or_io, options = {})
13
- @type = type
13
+ require 'csv'
14
+
14
15
  @path_or_io = path_or_io
15
- @options = DEFAULT_OPTIONS.merge(options)
16
- if @options[:smart] && !@path_or_io.is_a?(IO)
17
- @options[:col_sep] ||= infer_col_sep
18
- @options[:quote_char] ||= infer_quote_char
19
- end
16
+ @options = handle_options(options)
17
+ @type = handle_type(type)
20
18
  end
21
19
 
22
20
  def each
23
21
  return to_enum unless block_given?
24
- require 'csv'
25
- with_io do |io|
26
- ::CSV.new(io, **csv_options).each do |row|
22
+
23
+ with_csv do |csv|
24
+ csv.each do |row|
27
25
  yield tuple(row)
28
26
  end
29
27
  end
@@ -44,33 +42,70 @@ module Bmg
44
42
  row.to_hash.each_with_object({}){|(k,v),h| h[k.to_sym] = v }
45
43
  end
46
44
 
45
+ def handle_type(type)
46
+ return type if type.knows_attrlist?
47
+
48
+ type.with_attrlist(infer_attrlist)
49
+ end
50
+
51
+ def infer_attrlist
52
+ with_csv do |csv|
53
+ csv.each do |row|
54
+ return tuple(row).keys
55
+ end
56
+ end
57
+ end
58
+
59
+ def handle_options(options)
60
+ options = DEFAULT_OPTIONS.merge(options)
61
+ if options[:smart] && !@path_or_io.is_a?(IO)
62
+ options[:col_sep] ||= infer_col_sep
63
+ options[:quote_char] ||= infer_quote_char(options[:col_sep])
64
+ end
65
+ options
66
+ end
67
+
47
68
  def infer_col_sep
48
69
  sniff(text_portion, [",","\t",";"], ",")
49
70
  end
50
71
 
51
- def infer_quote_char
52
- sniff(text_portion, ["'","\""], "\"")
72
+ def infer_quote_char(col_sep)
73
+ sniff(text_portion, ['"',"'"], '"'){|quote|
74
+ /#{quote}#{col_sep}#{quote}|^#{quote}|#{quote}$/
75
+ }
53
76
  end
54
77
 
55
78
  def text_portion
56
- @text_portion ||= with_io{|io| io.readlines(10).join("\n") }
79
+ @text_portion ||= with_io{|io| io.readlines(50).join("\n") }
57
80
  end
58
81
 
59
82
  def with_io(&bl)
60
83
  case @path_or_io
61
84
  when IO, StringIO
85
+ @path_or_io.rewind if @path_or_io.respond_to?(:rewind)
62
86
  bl.call(@path_or_io)
63
87
  else
64
88
  File.open(@path_or_io, "r", &bl)
65
89
  end
66
90
  end
67
91
 
92
+ def with_csv(&bl)
93
+ with_io do |io|
94
+ yield ::CSV.new(io, **csv_options)
95
+ end
96
+ end
97
+
68
98
  # Finds the best candidate among `candidates` for a separator
69
99
  # found in `str`. If none is found, returns `default`.
70
- def sniff(str, candidates, default)
100
+ def sniff(str, candidates, default, &bl)
71
101
  snif = {}
72
102
  candidates.each {|delim|
73
- snif[delim] = str.count(delim)
103
+ counter = bl ? bl.call(delim) : delim
104
+ snif[delim] = if counter.is_a?(Regexp)
105
+ str.scan(counter).length
106
+ else
107
+ str.count(counter)
108
+ end
74
109
  }
75
110
  snif = snif.sort {|a,b| b[1] <=> a[1] }
76
111
  snif.size > 0 ? snif[0][0] : default
@@ -10,32 +10,27 @@ module Bmg
10
10
  }
11
11
 
12
12
  def initialize(type, path, options = {})
13
- @type = type
13
+ require 'roo'
14
14
  @path = path
15
15
  @options = DEFAULT_OPTIONS.merge(options)
16
+ @type = type.knows_attrlist? ? type : type.with_attrlist(infer_attrlist)
16
17
  end
17
18
 
18
19
  def each
19
20
  return to_enum unless block_given?
20
- require 'roo'
21
- xlsx = Roo::Spreadsheet.open(@path, @options)
22
- headers = nil
23
- xlsx.sheet(@options[:sheet])
24
- .each
25
- .drop(@options[:skip])
26
- .each_with_index
27
- .each do |row, i|
28
- if i==0
29
- headers = row.map{|c| c.to_s.strip.to_sym }
30
- else
31
- init = init_tuple(i)
32
- tuple = (0...headers.size)
33
- .each_with_object(init){|i,t|
34
- t[headers[i]] = row[i]
35
- }
36
- yield(tuple)
37
- end
38
- end
21
+
22
+ headers = type.attrlist
23
+ headers = headers[1..-1] if generate_row_num?
24
+ start_at = @options[:skip] + 2
25
+ end_at = spreadsheet.last_row
26
+ (start_at..end_at).each do |i|
27
+ row = spreadsheet.row(i)
28
+ init = init_tuple(i - start_at + 1)
29
+ tuple = (0...headers.size).each_with_object(init){|i,t|
30
+ t[headers[i]] = row[i]
31
+ }
32
+ yield(tuple)
33
+ end
39
34
  end
40
35
 
41
36
  def to_ast
@@ -49,17 +44,37 @@ module Bmg
49
44
 
50
45
  private
51
46
 
52
- def init_tuple(i)
47
+ def spreadsheet
48
+ @spreadsheet ||= Roo::Spreadsheet
49
+ .open(@path, @options)
50
+ .sheet(@options[:sheet])
51
+ end
52
+
53
+ def infer_attrlist
54
+ row = spreadsheet.row(1+@options[:skip])
55
+ attrlist = row.map{|c| c.to_s.strip.to_sym }
56
+ attrlist.unshift(row_num_name) if generate_row_num?
57
+ attrlist
58
+ end
59
+
60
+ def generate_row_num?
61
+ !!@options[:row_num]
62
+ end
63
+
64
+ def row_num_name
53
65
  case as = @options[:row_num]
54
- when TrueClass
55
- { :row_num => i }
56
- when FalseClass
57
- {}
58
- when Symbol
59
- { :"#{as}" => i }
66
+ when TrueClass then :row_num
67
+ when Symbol then as
68
+ else nil
60
69
  end
61
70
  end
62
71
 
72
+ def init_tuple(i)
73
+ return {} unless generate_row_num?
74
+
75
+ { row_num_name => i }
76
+ end
77
+
63
78
  end # class Excel
64
79
  end # module Reader
65
- end # module Bmg
80
+ end # module Bmg
@@ -5,6 +5,7 @@ module Bmg
5
5
 
6
6
  def initialize(operand)
7
7
  @operand = operand
8
+ @materialized = nil
8
9
  end
9
10
 
10
11
  def type
@@ -40,9 +41,9 @@ module Bmg
40
41
  private
41
42
 
42
43
  def _materialize
43
- return @operand if @operand.is_a?(Relation::InMemory)
44
+ return @materialized if @materialized
44
45
 
45
- @operand = Relation::InMemory.new(operand.type, operand.to_a)
46
+ @materialized = Relation::InMemory.new(operand.type, operand.to_a)
46
47
  end
47
48
 
48
49
  end # class Materialized
@@ -39,9 +39,6 @@ module Bmg
39
39
  subquery = All.new(builder).call(subquery)
40
40
  if commons.size == 0
41
41
  builder.exists(subquery)
42
- elsif commons.size == 1
43
- identifier = left.desaliaser(true)[commons.to_a.first]
44
- Predicate::Factory.in(identifier, Predicate::Factory.opaque(subquery))
45
42
  else
46
43
  join_pre = join_predicate(left, subquery, commons)
47
44
  subquery = expand_where_clause(subquery, join_pre)
data/lib/bmg/version.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  module Bmg
2
2
  module Version
3
3
  MAJOR = 0
4
- MINOR = 18
5
- TINY = 13
4
+ MINOR = 19
5
+ TINY = 0
6
6
  end
7
7
  VERSION = "#{Version::MAJOR}.#{Version::MINOR}.#{Version::TINY}"
8
8
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bmg
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.18.13
4
+ version: 0.19.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernard Lambeau
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-25 00:00:00.000000000 Z
11
+ date: 2022-04-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: predicate