bmg 0.18.9 → 0.18.13

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: e287adcc94d2a0a5a88604e90cb34895ff801b137478c3cfa8b32d2093e7289c
4
- data.tar.gz: 148775b4bdfbcb45099ed2587268243eef46b8a214d9bbf5f9f3abc9960764f2
2
+ SHA1:
3
+ metadata.gz: 0ceadf8947aa041841941225e88396cc37ff7319
4
+ data.tar.gz: 9c695d3305101ff4a73bcdef5e3788648e9b2d27
5
5
  SHA512:
6
- metadata.gz: ae86583f677f487bb3b6e71fa1a5ed07cc731bd927cf74716d68818d330809f86aaddb98c8a8c9848f68c3b0a8ba183996029ecf745db377d740b1c4da59b995
7
- data.tar.gz: a0fca7d1f3fa2ecc8097a0167d5ec9767a047b61af54212b16030dfe23a46c05e3597641c0c125c40f0652fbdc15d593e7201cc9b430467e90216af0630e4c5d
6
+ metadata.gz: 70db4550decd609934e1d8d643983766b5b50b9f0354b2405dfdc710b9580a885e4754c907ed5011856e905308af9647c029f0dd612657e72b45af0465eaced2
7
+ data.tar.gz: 5ed5e7f6d1d9baa8070112a36229e8961e4b5a531acbdac808fcf1f5c008fc91ae3ceadc5c3b4c1d0ace22ca6f861074e79b6d957498740a8fba3d5e99875068
data/lib/bmg/algebra.rb CHANGED
@@ -12,6 +12,7 @@ module Bmg
12
12
  protected :_allbut
13
13
 
14
14
  def autowrap(options = {})
15
+ return self if self.type.identity_autowrap?(options)
15
16
  _autowrap self.type.autowrap(options), options
16
17
  end
17
18
 
@@ -20,12 +21,12 @@ module Bmg
20
21
  end
21
22
  protected :_autowrap
22
23
 
23
- def autosummarize(by = [], summarization = {})
24
- _autosummarize type = self.type.autosummarize(by, summarization), by, summarization
24
+ def autosummarize(by = [], summarization = {}, options = {})
25
+ _autosummarize self.type.autosummarize(by, summarization, options), by, summarization, options
25
26
  end
26
27
 
27
- def _autosummarize(type, by, summarization)
28
- Operator::Autosummarize.new(type, self, by, summarization)
28
+ def _autosummarize(type, by, summarization, options)
29
+ Operator::Autosummarize.new(type, self, by, summarization, options)
29
30
  end
30
31
  protected :_autosummarize
31
32
 
@@ -11,16 +11,22 @@ module Bmg
11
11
  class Autosummarize
12
12
  include Operator::Unary
13
13
 
14
- def initialize(type, operand, by, sums)
14
+ DEFAULT_OPTIONS = {
15
+ default: :same
16
+ }
17
+
18
+ def initialize(type, operand, by, sums, options = {})
15
19
  @type = type
16
20
  @operand = operand
17
21
  @by = by
18
22
  @sums = sums.each_with_object({}){|(k,v),h| h[k] = to_summarizer(v) }
23
+ @options = DEFAULT_OPTIONS.merge(options)
24
+ @algo = build_algo
19
25
  end
20
26
 
21
27
  protected
22
28
 
23
- attr_reader :by, :sums
29
+ attr_reader :by, :sums, :options
24
30
 
25
31
  public
26
32
 
@@ -45,17 +51,17 @@ module Bmg
45
51
  h = {}
46
52
  @operand.each do |tuple|
47
53
  key = key(tuple)
48
- h[key] ||= init(key, tuple)
49
- h[key] = sum(h[key], tuple)
54
+ h[key] ||= @algo.init(tuple)
55
+ h[key] = @algo.sum(h[key], tuple)
50
56
  end
51
57
  h.each_pair do |k,v|
52
- h[k] = term(v)
58
+ h[k] = @algo.term(v)
53
59
  end
54
60
  h.values.each(&bl)
55
61
  end
56
62
 
57
63
  def to_ast
58
- [:autosummarize, operand.to_ast, by.dup, sums.dup]
64
+ [:autosummarize, operand.to_ast, by.dup, sums.dup, options.dup]
59
65
  end
60
66
 
61
67
  public ### for internal reasons
@@ -73,7 +79,7 @@ module Bmg
73
79
  else
74
80
  op = operand
75
81
  op = op.restrict(bottom)
76
- op = op.autosummarize(by, sums)
82
+ op = op.autosummarize(by, sums, options)
77
83
  op = op.restrict(top)
78
84
  op
79
85
  end
@@ -87,46 +93,86 @@ module Bmg
87
93
 
88
94
  private
89
95
 
96
+ def build_algo
97
+ case default = @options[:default]
98
+ when :same then Check.new(sums)
99
+ when :first then Trust.new(sums)
100
+ else
101
+ raise ArgumentError, "Unknown default summarizer: `#{default}`"
102
+ end
103
+ end
104
+
90
105
  # Returns the tuple determinant.
91
106
  def key(tuple)
92
107
  @by.map{|by| tuple[by] }
93
108
  end
94
109
 
95
- # Returns the initial tuple to use for a given determinant.
96
- def init(key, tuple)
97
- tuple.each_with_object({}){|(k,v),h|
98
- h.merge!(k => summarizer(k).init(v))
99
- }
100
- end
101
-
102
- # Returns the summarizer to use for a given key.
103
- def summarizer(k)
104
- @sums[k] || Same.new
105
- end
106
-
107
- # Sums `tuple` on `memo`, returning the new tuple to use as memo.
108
- def sum(memo, tuple)
109
- tuple.each_with_object(memo.dup){|(k,v),h|
110
- h.merge!(k => summarizer(k).sum(h[k], v))
111
- }
112
- end
113
-
114
- # Terminates the summarization of a given tuple.
115
- def term(tuple)
116
- tuple.each_with_object({}){|(k,v),h|
117
- h.merge!(k => summarizer(k).term(v))
118
- }
119
- end
120
-
121
110
  def to_summarizer(x)
122
111
  case x
123
- when :same then Same.new
124
- when :group then DistinctList.new
112
+ when :same then Same::INSTANCE
113
+ when :group then DistinctList::INSTANCE
125
114
  else
126
115
  x
127
116
  end
128
117
  end
129
118
 
119
+ class Check
120
+ def initialize(sums)
121
+ @sums = sums
122
+ end
123
+ attr_reader :sums
124
+
125
+ def summarizer(k)
126
+ @sums[k] ||= Same::INSTANCE
127
+ end
128
+
129
+ def init(tuple)
130
+ tuple.each_with_object({}){|(k,v),h|
131
+ h.merge!(k => summarizer(k).init(v))
132
+ }
133
+ end
134
+
135
+ def sum(memo, tuple)
136
+ tuple.each_with_object(memo.dup){|(k,v),h|
137
+ h.merge!(k => summarizer(k).sum(h[k], v))
138
+ }
139
+ end
140
+
141
+ def term(tuple)
142
+ tuple.each_with_object({}){|(k,v),h|
143
+ h.merge!(k => summarizer(k).term(v))
144
+ }
145
+ end
146
+ end # class Check
147
+
148
+ class Trust
149
+ def initialize(sums)
150
+ @sums = sums
151
+ end
152
+ attr_reader :sums
153
+
154
+ # Returns the initial tuple to use for a given determinant.
155
+ def init(tuple)
156
+ sums.each_with_object(tuple.dup){|(attribute,summarizer),new_tuple|
157
+ new_tuple[attribute] = summarizer.init(tuple[attribute])
158
+ }
159
+ end
160
+
161
+ # Sums `tuple` on `memo`, returning the new tuple to use as memo.
162
+ def sum(memo, tuple)
163
+ sums.each_with_object(memo.dup){|(attribute,summarizer),new_tuple|
164
+ new_tuple[attribute] = summarizer.sum(memo[attribute], tuple[attribute])
165
+ }
166
+ end
167
+
168
+ # Terminates the summarization of a given tuple.
169
+ def term(tuple)
170
+ sums.each_with_object(tuple.dup){|(attribute,summarizer),new_tuple|
171
+ new_tuple[attribute] = summarizer.term(tuple[attribute])
172
+ }
173
+ end
174
+ end # class Trust
175
+
130
176
  #
131
177
  # Summarizes by enforcing that the same dependent is observed for a given
132
178
  # determinant, returning the dependent as summarization.
@@ -138,7 +184,7 @@ module Bmg
138
184
  end
139
185
 
140
186
  def sum(v1, v2)
141
- raise "Same values expected, got `#{v1}` vs. `#{v2}`" unless v1 == v2
187
+ raise TypeError, "Same values expected, got `#{v1}` vs. `#{v2}`" unless v1 == v2
142
188
  v1
143
189
  end
144
190
 
@@ -151,6 +197,7 @@ module Bmg
151
197
  end
152
198
  alias :to_s :inspect
153
199
 
200
+ INSTANCE = new
154
201
  end # class Same
155
202
 
156
203
  #
@@ -183,6 +230,7 @@ module Bmg
183
230
  end
184
231
  alias :to_s :inspect
185
232
 
233
+ INSTANCE = new
186
234
  end # class DistinctList
187
235
 
188
236
  #
@@ -26,6 +26,12 @@ module Bmg
26
26
  :split => "_"
27
27
  }
28
28
 
29
+ class << self
30
+ def separator(options)
31
+ options[:split] || DEFAULT_OPTIONS[:split]
32
+ end
33
+ end
34
+
29
35
  def initialize(type, operand, options = {})
30
36
  @type = type
31
37
  @operand = operand
@@ -32,7 +32,8 @@ module Bmg
32
32
  def each(&bl)
33
33
  return to_enum unless block_given?
34
34
  page_size = options[:page_size]
35
- @operand.to_a
35
+ @operand
36
+ .to_a
36
37
  .sort(&comparator)
37
38
  .drop(page_size * (page_index-1))
38
39
  .take(page_size)
@@ -46,7 +47,7 @@ module Bmg
46
47
  protected ### inspect
47
48
 
48
49
  def comparator
49
- Ordering.new(@ordering).comparator
50
+ @comparator ||= Ordering.new(@ordering).comparator
50
51
  end
51
52
 
52
53
  def args
@@ -19,14 +19,14 @@ module Bmg
19
19
  public
20
20
 
21
21
  def _count
22
- operand._count
22
+ _materialize._count
23
23
  end
24
24
 
25
25
  public
26
26
 
27
27
  def each(&bl)
28
- @operand = Relation::InMemory.new(operand.type, operand.to_a) unless @operand.is_a?(Relation::InMemory)
29
- @operand.each(&bl)
28
+ return to_enum unless block_given?
29
+ _materialize.each(&bl)
30
30
  end
31
31
 
32
32
  def to_ast
@@ -37,6 +37,14 @@ module Bmg
37
37
  []
38
38
  end
39
39
 
40
+ private
41
+
42
+ def _materialize
43
+ return @operand if @operand.is_a?(Relation::InMemory)
44
+
45
+ @operand = Relation::InMemory.new(operand.type, operand.to_a)
46
+ end
47
+
40
48
  end # class Materialized
41
49
  end # module Relation
42
50
  end # module Bmg
@@ -24,13 +24,27 @@ module Bmg
24
24
  protected :type=
25
25
 
26
26
  def each(&bl)
27
- spy.call(self) if bl
28
- operand.each(&bl)
27
+ return enum_for(:each) unless bl
28
+
29
+ if spy.respond_to?(:measure)
30
+ spy.measure(self) do
31
+ operand.each(&bl)
32
+ end
33
+ else
34
+ spy.call(self)
35
+ operand.each(&bl)
36
+ end
29
37
  end
30
38
 
31
39
  def count
32
- spy.call(self) if bl
33
- operand.count
40
+ if spy.respond_to?(:measure)
41
+ spy.measure(self) do
42
+ operand.count
43
+ end
44
+ else
45
+ spy.call(self)
46
+ operand.count
47
+ end
34
48
  end
35
49
 
36
50
  def to_ast
@@ -213,8 +213,7 @@ module Bmg
213
213
  def _collect_joins(sexpr, joins)
214
214
  case sexpr.first
215
215
  when :and
216
- _collect_joins(sexpr[1], joins)
217
- _collect_joins(sexpr[2], joins)
216
+ sexpr[1..-1].each{ |term| _collect_joins(term, joins) }
218
217
  when :eq
219
218
  joins << sexpr
220
219
  else
@@ -11,13 +11,26 @@ module Bmg
11
11
  end
12
12
 
13
13
  def comparator
14
- @comparator ||= ->(t1, t2) {
15
- attrs.each do |(attr,direction)|
16
- c = t1[attr] <=> t2[attr]
17
- return (direction == :desc ? -c : c) unless c==0
14
+ @comparator ||= ->(t1, t2) { compare_attrs(t1, t2) }
15
+ end
16
+
17
+ def compare_attrs(t1, t2)
18
+ attrs.each do |(attr,direction)|
19
+ a1, a2 = t1[attr], t2[attr]
20
+ if a1.nil? && a2.nil?
21
+ 0
22
+ elsif a1.nil?
23
+ return direction == :desc ? -1 : 1
24
+ elsif a2.nil?
25
+ return direction == :desc ? 1 : -1
26
+ elsif a1.respond_to?(:<=>)
27
+ c = a1 <=> a2
28
+ unless c.nil? || c==0
29
+ return direction == :desc ? -c : c
30
+ end
18
31
  end
19
- 0
20
- }
32
+ end
33
+ 0
21
34
  end
22
35
 
23
36
  end # class Ordering
data/lib/bmg/type.rb CHANGED
@@ -103,8 +103,15 @@ module Bmg
103
103
  }
104
104
  end
105
105
 
106
+ def identity_autowrap?(options)
107
+ return false unless knows_attrlist?
108
+
109
+ sep = Operator::Autowrap.separator(options)
110
+ self.attrlist.all?{|a| a.to_s.index(sep).nil? }
111
+ end
112
+
106
113
  def autowrap(options)
107
- sep = options[:split] || Operator::Autowrap::DEFAULT_OPTIONS[:split]
114
+ sep = Operator::Autowrap.separator(options)
108
115
  splitter = ->(a){ a.to_s.split(sep).first }
109
116
  is_split = ->(a){ a.to_s.split(sep).size > 1 }
110
117
  dup.tap{|x|
@@ -115,7 +122,7 @@ module Bmg
115
122
  }
116
123
  end
117
124
 
118
- def autosummarize(by, summarization)
125
+ def autosummarize(by, summarization, options)
119
126
  known_attributes!(by + summarization.keys) if typechecked? && knows_attrlist?
120
127
  dup.tap{|x|
121
128
  x.attrlist = nil
data/lib/bmg/version.rb CHANGED
@@ -2,7 +2,7 @@ module Bmg
2
2
  module Version
3
3
  MAJOR = 0
4
4
  MINOR = 18
5
- TINY = 9
5
+ TINY = 13
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.9
4
+ version: 0.18.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernard Lambeau
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-29 00:00:00.000000000 Z
11
+ date: 2022-01-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: predicate
@@ -16,20 +16,20 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '2.5'
19
+ version: '2.6'
20
20
  - - ">="
21
21
  - !ruby/object:Gem::Version
22
- version: 2.5.0
22
+ version: 2.6.0
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - "~>"
28
28
  - !ruby/object:Gem::Version
29
- version: '2.5'
29
+ version: '2.6'
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
- version: 2.5.0
32
+ version: 2.6.0
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: path
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -317,7 +317,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
317
317
  - !ruby/object:Gem::Version
318
318
  version: '0'
319
319
  requirements: []
320
- rubygems_version: 3.1.4
320
+ rubyforge_project:
321
+ rubygems_version: 2.6.14.4
321
322
  signing_key:
322
323
  specification_version: 4
323
324
  summary: Bmg is Alf's successor.