bmg 0.2.0 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bc75e7b5602e1f76e3581009746302b3a546f3f8
4
- data.tar.gz: 5dee61974de7699b5ef4957cd2714d5d241df830
3
+ metadata.gz: e6536b48ec764ca63860c01d8f75b689449c0d29
4
+ data.tar.gz: 4a5f92f4e5dc65f723e419ccbfe89dd424aa27ef
5
5
  SHA512:
6
- metadata.gz: cdad32c048da1719f153a16f355a79b13cd68cd18cf017c47041b7d73992f18c19cbdf9c5c32cf366e8801a0ac98a0ef84237120a7f8e59e9d3274feecd8a715
7
- data.tar.gz: 28e09b93f01a6aaa0c8e95adba0bf8b417dbf501e9b5b221c8593a5f53f9cdebe04fb636b7fe641ddf41ba3ff6a706de0ab6c9d4c70b70f49f6a9c055e3041cd
6
+ metadata.gz: 3d9fff6fdabf0f3be88b94cff5a7896d0625d82c47772683c3f40156c7cefa46387c95131c261aeb953978aec013e16acae40d203a9554233a61604fea59e5bb
7
+ data.tar.gz: 6b8b239b5da4002e2ee96a0946acf7b9636f465f15eeac0f5ee227dc4fcccab68fa00b4b4a32a4827b0e9336e5f46a73036397dabe9855e6ea14351a56279fe8
data/lib/bmg.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'path'
2
+ require 'predicate'
2
3
  module Bmg
3
4
 
4
5
  def csv(path, options = {})
@@ -14,6 +15,9 @@ module Bmg
14
15
  end
15
16
  require_relative 'bmg/version'
16
17
  require_relative 'bmg/error'
17
- require_relative 'bmg/operator'
18
+ require_relative 'bmg/algebra'
19
+ require_relative 'bmg/type'
18
20
  require_relative 'bmg/relation'
21
+ require_relative 'bmg/leaf'
22
+ require_relative 'bmg/operator'
19
23
  require_relative 'bmg/reader'
@@ -0,0 +1,95 @@
1
+ module Bmg
2
+ module Algebra
3
+
4
+ def allbut(butlist = [])
5
+ _allbut self.type.allbut(butlist), butlist
6
+ end
7
+
8
+ def _allbut(type, butlist)
9
+ Operator::Allbut.new(type, self, butlist)
10
+ end
11
+ protected :_allbut
12
+
13
+ def autowrap(options = {})
14
+ _autowrap self.type.autowrap(options), options
15
+ end
16
+
17
+ def _autowrap(type, options)
18
+ Operator::Autowrap.new(type, self, options)
19
+ end
20
+ protected :_autowrap
21
+
22
+ def autosummarize(by = [], summarization = {})
23
+ _autosummarize type = self.type.autosummarize(by, summarization), by, summarization
24
+ end
25
+
26
+ def _autosummarize(type, by, summarization)
27
+ Operator::Autosummarize.new(type, self, by, summarization)
28
+ end
29
+ protected :_autosummarize
30
+
31
+ def constants(cs = {})
32
+ _constants self.type.constants(cs), cs
33
+ end
34
+
35
+ def _constants(type, cs)
36
+ Operator::Constants.new(type, self, cs)
37
+ end
38
+ protected :_constants
39
+
40
+ def extend(extension = {})
41
+ _extend self.type.extend(extension), extension
42
+ end
43
+
44
+ def _extend(type, extension)
45
+ Operator::Extend.new(type, self, extension)
46
+ end
47
+ protected :_extend
48
+
49
+ def image(right, as = :image, on = [], options = {})
50
+ _image self.type.image(right, as, on, options), right, as, on, options
51
+ end
52
+
53
+ def _image(type, right, as, on, options)
54
+ Operator::Image.new(type, self, right, as, on, options)
55
+ end
56
+ protected :_image
57
+
58
+ def project(attrlist = [])
59
+ _project self.type.project(attrlist), attrlist
60
+ end
61
+
62
+ def _project(type, attrlist)
63
+ Operator::Project.new(type, self, attrlist)
64
+ end
65
+ protected :_project
66
+
67
+ def rename(renaming = {})
68
+ _rename self.type.rename(renaming), renaming
69
+ end
70
+
71
+ def _rename(type, renaming)
72
+ Operator::Rename.new(type, self, renaming)
73
+ end
74
+ protected :_rename
75
+
76
+ def restrict(predicate)
77
+ _restrict self.type.restrict(predicate), Predicate.coerce(predicate)
78
+ end
79
+
80
+ def _restrict(type, predicate)
81
+ Operator::Restrict.new(type, self, predicate)
82
+ end
83
+ protected :_restrict
84
+
85
+ def union(other)
86
+ _union self.type.union(other.type), other
87
+ end
88
+
89
+ def _union(type, other)
90
+ Operator::Union.new(type, self, other)
91
+ end
92
+ protected :_union
93
+
94
+ end # module Algebra
95
+ end # module Bmg
@@ -0,0 +1,18 @@
1
+ module Bmg
2
+ class Leaf
3
+ include Relation
4
+
5
+ def initialize(type, operand)
6
+ @operand = operand
7
+ @type = type
8
+ end
9
+ attr_reader :type, :operand
10
+
11
+ public
12
+
13
+ def each(&bl)
14
+ @operand.each(&bl)
15
+ end
16
+
17
+ end
18
+ end
@@ -1,15 +1,16 @@
1
1
  module Bmg
2
2
  module Operator
3
-
4
- def to_a
5
- to_enum(:each).to_a
6
- end
3
+ include Relation
7
4
 
8
5
  end
9
6
  end
10
7
  require_relative 'operator/allbut'
11
8
  require_relative 'operator/autosummarize'
12
9
  require_relative 'operator/autowrap'
10
+ require_relative 'operator/constants'
11
+ require_relative 'operator/extend'
12
+ require_relative 'operator/image'
13
13
  require_relative 'operator/project'
14
14
  require_relative 'operator/rename'
15
- require_relative 'operator/extend'
15
+ require_relative 'operator/restrict'
16
+ require_relative 'operator/union'
@@ -17,15 +17,23 @@ module Bmg
17
17
  class Allbut
18
18
  include Operator
19
19
 
20
- def initialize(operand, butlist)
20
+ def initialize(type, operand, butlist)
21
+ @type = type
21
22
  @operand = operand
22
23
  @butlist = butlist
23
24
  end
25
+ attr_reader :type
26
+
27
+ protected
28
+
29
+ attr_reader :operand, :butlist
30
+
31
+ public
24
32
 
25
33
  def each
26
34
  seen = {}
27
35
  @operand.each do |tuple|
28
- allbuted = allbut(tuple)
36
+ allbuted = tuple_allbut(tuple)
29
37
  unless seen.has_key?(allbuted)
30
38
  yield(allbuted)
31
39
  seen[allbuted] = true
@@ -33,9 +41,15 @@ module Bmg
33
41
  end
34
42
  end
35
43
 
44
+ protected ### optimization
45
+
46
+ def _restrict(type, predicate)
47
+ operand.restrict(predicate).allbut(butlist)
48
+ end
49
+
36
50
  private
37
51
 
38
- def allbut(tuple)
52
+ def tuple_allbut(tuple)
39
53
  tuple.delete_if{|k,_| @butlist.include?(k) }
40
54
  end
41
55
 
@@ -11,11 +11,19 @@ module Bmg
11
11
  class Autosummarize
12
12
  include Operator
13
13
 
14
- def initialize(operand, by, sums)
14
+ def initialize(type, operand, by, sums)
15
+ @type = type
15
16
  @operand = operand
16
17
  @by = by
17
18
  @sums = sums.each_with_object({}){|(k,v),h| h[k] = to_summarizer(v) }
18
19
  end
20
+ attr_reader :type
21
+
22
+ protected
23
+
24
+ attr_reader :operand, :by, :sums
25
+
26
+ public
19
27
 
20
28
  def each(&bl)
21
29
  h = {}
@@ -25,11 +25,19 @@ module Bmg
25
25
  :split => "_"
26
26
  }
27
27
 
28
- def initialize(operand, options = {})
28
+ def initialize(type, operand, options = {})
29
+ @type = type
29
30
  @operand = operand
30
31
  @options = DEFAULT_OPTIONS.merge(options)
31
32
  @options[:postprocessor] = NoLeftJoinNoise.new(@options[:postprocessor])
32
33
  end
34
+ attr_reader :type
35
+
36
+ private
37
+
38
+ attr_reader :operand, :options
39
+
40
+ public
33
41
 
34
42
  def each
35
43
  @operand.each do |tuple|
@@ -0,0 +1,57 @@
1
+ module Bmg
2
+ module Operator
3
+ #
4
+ # Constants operator.
5
+ #
6
+ # Extends operand's tuples with attributes given at construction.
7
+ # This is a special case of an extension, where the values are
8
+ # statically known.
9
+ #
10
+ class Constants
11
+ include Operator
12
+
13
+ def initialize(type, operand, constants)
14
+ @type = type
15
+ @operand = operand
16
+ @constants = constants
17
+ end
18
+ attr_reader :type
19
+
20
+ protected
21
+
22
+ attr_reader :operand, :constants
23
+
24
+ public
25
+
26
+ def each
27
+ @operand.each do |tuple|
28
+ yield extend_it(tuple)
29
+ end
30
+ end
31
+
32
+ protected ### optimization
33
+
34
+ def _restrict(type, predicate)
35
+ top_p, bottom_p = predicate.and_split(constants.keys)
36
+ if top_p == predicate
37
+ super
38
+ else
39
+ result = operand
40
+ result = result.restrict(bottom_p) unless bottom_p.tautology?
41
+ result = result.constants(constants)
42
+ result = result.restrict(top_p) unless top_p.tautology?
43
+ result
44
+ end
45
+ rescue Predicate::NotSupportedError
46
+ super
47
+ end
48
+
49
+ private
50
+
51
+ def extend_it(tuple)
52
+ tuple.merge(@constants)
53
+ end
54
+
55
+ end # class Constants
56
+ end # module Operator
57
+ end # module Bmg
@@ -13,10 +13,18 @@ module Bmg
13
13
  class Extend
14
14
  include Operator
15
15
 
16
- def initialize(operand, extension)
16
+ def initialize(type, operand, extension)
17
+ @type = type
17
18
  @operand = operand
18
19
  @extension = extension
19
20
  end
21
+ attr_reader :type
22
+
23
+ protected
24
+
25
+ attr_reader :operand, :extension
26
+
27
+ public
20
28
 
21
29
  def each
22
30
  @operand.each do |tuple|
@@ -0,0 +1,73 @@
1
+ module Bmg
2
+ module Operator
3
+ #
4
+ # Image operator.
5
+ #
6
+ # Extends each tuple with its image in right.
7
+ #
8
+ class Image
9
+ include Operator
10
+
11
+ DEFAULT_OPTIONS = {
12
+
13
+ # Whether we need to convert each image as an Array,
14
+ # instead of keeping a Relation instance
15
+ array: false
16
+
17
+ }
18
+
19
+ def initialize(type, left, right, as, on, options = {})
20
+ @type = type
21
+ @left = left
22
+ @right = right
23
+ @as = as
24
+ @on = on
25
+ @options = DEFAULT_OPTIONS.merge(options)
26
+ end
27
+ attr_reader :type
28
+
29
+ private
30
+
31
+ attr_reader :left, :right, :as, :on, :options
32
+
33
+ public
34
+
35
+ def each
36
+ index = Hash.new{|h,k| h[k] = empty_image }
37
+ right.each_with_object(index) do |t, index|
38
+ key = tuple_project(t, on)
39
+ index[key].operand << tuple_image(t, on)
40
+ end
41
+ if options[:array]
42
+ index = index.each_with_object({}) do |(k,v),ix|
43
+ ix[k] = v.to_a
44
+ end
45
+ end
46
+ left.each do |tuple|
47
+ key = tuple_project(tuple, on)
48
+ image = index[key] || (options[:array] ? [] : empty_image)
49
+ yield tuple.merge(as => image)
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ def tuple_project(tuple, on)
56
+ on.each_with_object({}){|k,t| t[k] = tuple[k] }
57
+ end
58
+
59
+ def tuple_image(tuple, on)
60
+ tuple.dup.delete_if{|k,_| on.include?(k) }
61
+ end
62
+
63
+ def image_type
64
+ type[as]
65
+ end
66
+
67
+ def empty_image
68
+ Leaf.new(image_type, Set.new)
69
+ end
70
+
71
+ end # class Project
72
+ end # module Operator
73
+ end # module Bmg
@@ -16,10 +16,18 @@ module Bmg
16
16
  class Project
17
17
  include Operator
18
18
 
19
- def initialize(operand, attrlist)
19
+ def initialize(type, operand, attrlist)
20
+ @type = type
20
21
  @operand = operand
21
22
  @attrlist = attrlist
22
23
  end
24
+ attr_reader :type
25
+
26
+ private
27
+
28
+ attr_reader :operand, :attrlist
29
+
30
+ public
23
31
 
24
32
  def each
25
33
  seen = {}
@@ -32,6 +40,12 @@ module Bmg
32
40
  end
33
41
  end
34
42
 
43
+ protected ### optimization
44
+
45
+ def _restrict(type, predicate)
46
+ operand.restrict(predicate).project(attrlist)
47
+ end
48
+
35
49
  private
36
50
 
37
51
  def project(tuple)
@@ -16,10 +16,18 @@ module Bmg
16
16
  class Rename
17
17
  include Operator
18
18
 
19
- def initialize(operand, renaming)
19
+ def initialize(type, operand, renaming)
20
+ @type = type
20
21
  @operand = operand
21
22
  @renaming = renaming
22
23
  end
24
+ attr_reader :type
25
+
26
+ private
27
+
28
+ attr_reader :operand, :renaming
29
+
30
+ public
23
31
 
24
32
  def each
25
33
  @operand.each do |tuple|
@@ -0,0 +1,39 @@
1
+ module Bmg
2
+ module Operator
3
+ #
4
+ # Restrict operator.
5
+ #
6
+ # Filters operand's tuples to those that meet the predicate received
7
+ # at construction.
8
+ #
9
+ class Restrict
10
+ include Operator
11
+
12
+ def initialize(type, operand, predicate)
13
+ @type = type
14
+ @operand = operand
15
+ @predicate = predicate
16
+ end
17
+ attr_reader :type
18
+
19
+ protected
20
+
21
+ attr_reader :operand, :predicate
22
+
23
+ public
24
+
25
+ def each
26
+ @operand.each do |tuple|
27
+ yield(tuple) if @predicate.evaluate(tuple)
28
+ end
29
+ end
30
+
31
+ protected
32
+
33
+ def _restrict(type, predicate)
34
+ Restrict.new(type, @operand, @predicate & predicate)
35
+ end
36
+
37
+ end # class Restrict
38
+ end # module Operator
39
+ end # module Bmg
@@ -0,0 +1,62 @@
1
+ module Bmg
2
+ module Operator
3
+ #
4
+ # Union operator.
5
+ #
6
+ # Returns all tuples of the left operand followed by all
7
+ # tuples from the right operand.
8
+ #
9
+ # By default, this operator strips duplicates, as of relational
10
+ # theory. Please set the `:all` option to true to avoid this
11
+ # behavior and save execution time.
12
+ #
13
+ class Union
14
+ include Operator
15
+
16
+ DEFAULT_OPTIONS = {
17
+ all: false
18
+ }
19
+
20
+ def initialize(type, left, right, options = {})
21
+ @type = type
22
+ @left = left
23
+ @right = right
24
+ @options = DEFAULT_OPTIONS.merge(options)
25
+ end
26
+ attr_reader :type
27
+
28
+ protected
29
+
30
+ attr_reader :left, :right, :options
31
+
32
+ public
33
+
34
+ def all?
35
+ @options[:all]
36
+ end
37
+
38
+ def each(&bl)
39
+ if all?
40
+ @left.each(&bl)
41
+ @right.each(&bl)
42
+ else
43
+ seen = {}
44
+ @left.each do |tuple|
45
+ yield(tuple)
46
+ seen[tuple] = true
47
+ end
48
+ @right.each do |tuple|
49
+ yield(tuple) unless seen.has_key?(tuple)
50
+ end
51
+ end
52
+ end
53
+
54
+ protected ### optimization
55
+
56
+ def _restrict(type, predicate)
57
+ left.restrict(predicate).union(right.restrict(predicate))
58
+ end
59
+
60
+ end # class Union
61
+ end # module Operator
62
+ end # module Bmg
@@ -1,15 +1,10 @@
1
1
  module Bmg
2
- class Relation
2
+ module Relation
3
3
  include Enumerable
4
+ include Algebra
4
5
 
5
- def initialize(operand)
6
- @operand = operand
7
- end
8
-
9
- ## Consumption methods
10
-
11
- def each(&bl)
12
- @operand.each(&bl)
6
+ def self.new(operand, type = Type::ANY)
7
+ operand.is_a?(Relation) ? operand : Leaf.new(type, operand)
13
8
  end
14
9
 
15
10
  # Private helper to implement `one` and `one_or_nil`
@@ -36,31 +31,5 @@ module Bmg
36
31
  one_or_yield{ nil }
37
32
  end
38
33
 
39
- ## Relational algebra
40
-
41
- def allbut(butlist = [])
42
- Relation.new Operator::Allbut.new(@operand, butlist)
43
- end
44
-
45
- def autowrap(options = {})
46
- Relation.new Operator::Autowrap.new(@operand, options)
47
- end
48
-
49
- def autosummarize(by = [], summarization = {})
50
- Relation.new Operator::Autosummarize.new(@operand, by, summarization)
51
- end
52
-
53
- def extend(extension = {})
54
- Relation.new Operator::Extend.new(@operand, extension)
55
- end
56
-
57
- def project(attrlist = [])
58
- Relation.new Operator::Project.new(@operand, attrlist)
59
- end
60
-
61
- def rename(renaming = {})
62
- Relation.new Operator::Rename.new(@operand, renaming)
63
- end
64
-
65
- end # class Relation
34
+ end # module Relation
66
35
  end # module Bmg
@@ -0,0 +1,11 @@
1
+ require 'sequel'
2
+ require 'predicate/sequel'
3
+ module Bmg
4
+
5
+ def sequel(dataset, type = Type::ANY)
6
+ Sequel::Relation.new(type, dataset)
7
+ end
8
+ module_function :sequel
9
+
10
+ end
11
+ require_relative 'sequel/relation'
@@ -0,0 +1,32 @@
1
+ module Bmg
2
+ module Sequel
3
+ class Relation
4
+ include Bmg::Relation
5
+
6
+ def initialize(type, dataset)
7
+ @type = type
8
+ @dataset = dataset
9
+ end
10
+ attr_reader :type
11
+
12
+ protected
13
+
14
+ attr_reader :dataset
15
+
16
+ public
17
+
18
+ def each(&bl)
19
+ @dataset.each(&bl)
20
+ end
21
+
22
+ protected ### optimization
23
+
24
+ def _restrict(type, predicate)
25
+ Relation.new type, dataset.where(predicate.to_sequel)
26
+ rescue NotImplementedError, Predicate::NotSupportedError
27
+ super
28
+ end
29
+
30
+ end # class Relation
31
+ end # module Operator
32
+ end # module Bmg
@@ -0,0 +1,51 @@
1
+ module Bmg
2
+ class Type
3
+
4
+ ANY = Type.new
5
+
6
+ def [](attribute)
7
+ ANY
8
+ end
9
+
10
+ def allbut(butlist)
11
+ ANY
12
+ end
13
+
14
+ def autowrap(options)
15
+ ANY
16
+ end
17
+
18
+ def autosummarize(by, summarization)
19
+ ANY
20
+ end
21
+
22
+ def constants(cs)
23
+ ANY
24
+ end
25
+
26
+ def extend(extension)
27
+ ANY
28
+ end
29
+
30
+ def image(right, as, on, options)
31
+ ANY
32
+ end
33
+
34
+ def project(attrlist)
35
+ ANY
36
+ end
37
+
38
+ def rename(renaming)
39
+ ANY
40
+ end
41
+
42
+ def restrict(predicate)
43
+ ANY
44
+ end
45
+
46
+ def union(other)
47
+ ANY
48
+ end
49
+
50
+ end # class Type
51
+ end # module Bmg
@@ -1,7 +1,7 @@
1
1
  module Bmg
2
2
  module Version
3
3
  MAJOR = 0
4
- MINOR = 2
4
+ MINOR = 3
5
5
  TINY = 0
6
6
  end
7
7
  VERSION = "#{Version::MAJOR}.#{Version::MINOR}.#{Version::TINY}"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bmg
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernard Lambeau
@@ -10,6 +10,26 @@ bindir: bin
10
10
  cert_chain: []
11
11
  date: 2017-11-20 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: predicate
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.1'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.1.1
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '1.1'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.1.1
13
33
  - !ruby/object:Gem::Dependency
14
34
  name: rake
15
35
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +86,34 @@ dependencies:
66
86
  - - ">="
67
87
  - !ruby/object:Gem::Version
68
88
  version: '2.7'
89
+ - !ruby/object:Gem::Dependency
90
+ name: sequel
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ - !ruby/object:Gem::Dependency
104
+ name: sqlite3
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
69
117
  description: Bmg is Alf's relational algebra for ruby, but much simpler and lighter
70
118
  than Alf itself
71
119
  email: blambeau@gmail.com
@@ -78,18 +126,27 @@ files:
78
126
  - README.md
79
127
  - Rakefile
80
128
  - lib/bmg.rb
129
+ - lib/bmg/algebra.rb
81
130
  - lib/bmg/error.rb
131
+ - lib/bmg/leaf.rb
82
132
  - lib/bmg/operator.rb
83
133
  - lib/bmg/operator/allbut.rb
84
134
  - lib/bmg/operator/autosummarize.rb
85
135
  - lib/bmg/operator/autowrap.rb
136
+ - lib/bmg/operator/constants.rb
86
137
  - lib/bmg/operator/extend.rb
138
+ - lib/bmg/operator/image.rb
87
139
  - lib/bmg/operator/project.rb
88
140
  - lib/bmg/operator/rename.rb
141
+ - lib/bmg/operator/restrict.rb
142
+ - lib/bmg/operator/union.rb
89
143
  - lib/bmg/reader.rb
90
144
  - lib/bmg/reader/csv.rb
91
145
  - lib/bmg/reader/excel.rb
92
146
  - lib/bmg/relation.rb
147
+ - lib/bmg/sequel.rb
148
+ - lib/bmg/sequel/relation.rb
149
+ - lib/bmg/type.rb
93
150
  - lib/bmg/version.rb
94
151
  - tasks/gem.rake
95
152
  - tasks/test.rake