sequel_temporal 0.1.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.
- data/.gitignore +4 -0
- data/.travis.yml +5 -0
- data/Gemfile +2 -0
- data/README.md +47 -0
- data/Rakefile +6 -0
- data/lib/sequel/plugins/temporal.rb +151 -0
- data/lib/sequel_temporal.rb +1 -0
- data/sequel_temporal.gemspec +24 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/support/temporal_matchers.rb +40 -0
- data/spec/temporal_spec.rb +222 -0
- metadata +122 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
sequel_temporal
|
2
|
+
=================
|
3
|
+
|
4
|
+
Temporal versioning for sequel.
|
5
|
+
|
6
|
+
Dependencies
|
7
|
+
------------
|
8
|
+
|
9
|
+
* Ruby >= 1.9.2
|
10
|
+
* gem "sequel", "~> 3.30.0"
|
11
|
+
|
12
|
+
Usage
|
13
|
+
-----
|
14
|
+
|
15
|
+
* Declare temporality inside your model:
|
16
|
+
|
17
|
+
class HotelPriceVersion < Sequel::Model
|
18
|
+
end
|
19
|
+
|
20
|
+
class HotelPrice < Sequel::Model
|
21
|
+
plugin :temporal, version_class: HotelPriceVersion
|
22
|
+
end
|
23
|
+
|
24
|
+
* You can now create a hotel price with versions:
|
25
|
+
|
26
|
+
price = HotelPrice.new
|
27
|
+
price.update_attributes price: 18
|
28
|
+
|
29
|
+
* To show all versions:
|
30
|
+
|
31
|
+
price.versions
|
32
|
+
|
33
|
+
* To get current version:
|
34
|
+
|
35
|
+
price.current_version
|
36
|
+
|
37
|
+
* Look at the specs for more usage patterns.
|
38
|
+
|
39
|
+
Build Status
|
40
|
+
------------
|
41
|
+
|
42
|
+
[](http://travis-ci.org/TalentBox/sequel_bitemporal)
|
43
|
+
|
44
|
+
License
|
45
|
+
-------
|
46
|
+
|
47
|
+
sequel_temporal is Copyright © 2011 TalentBox SA. It is free software, and may be redistributed under the terms specified in the LICENSE file.
|
data/Rakefile
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
module Sequel
|
2
|
+
module Plugins
|
3
|
+
module Temporal
|
4
|
+
def self.at(time)
|
5
|
+
raise ArgumentError, "requires a block" unless block_given?
|
6
|
+
key = :sequel_plugins_temporal_now
|
7
|
+
previous, Thread.current[key] = Thread.current[key], time.to_time
|
8
|
+
yield
|
9
|
+
Thread.current[key] = previous
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.now
|
13
|
+
Thread.current[:sequel_plugins_temporal_now] || Time.now
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.configure(master, opts = {})
|
17
|
+
version = opts[:version_class]
|
18
|
+
raise Error, "please specify version class to use for temporal plugin" unless version
|
19
|
+
required = [:master_id, :created_at, :expired_at]
|
20
|
+
missing = required - version.columns
|
21
|
+
raise Error, "temporal plugin requires the following missing column#{"s" if missing.size>1} on version class: #{missing.join(", ")}" unless missing.empty?
|
22
|
+
master.instance_eval do
|
23
|
+
@version_class = version
|
24
|
+
base_alias = name ? underscore(demodulize(name)) : table_name
|
25
|
+
@versions_alias = "#{base_alias}_versions".to_sym
|
26
|
+
@current_version_alias = "#{base_alias}_current_version".to_sym
|
27
|
+
end
|
28
|
+
master.one_to_many :versions, class: version, key: :master_id, graph_alias_base: master.versions_alias
|
29
|
+
master.one_to_one :current_version, class: version, key: :master_id, graph_alias_base: master.current_version_alias, :graph_block=>(proc do |j, lj, js|
|
30
|
+
n = ::Sequel::Plugins::Temporal.now
|
31
|
+
e = :expired_at.qualify(j)
|
32
|
+
(:created_at.qualify(j) <= n) & ({e=>nil} | (e > n))
|
33
|
+
end) do |ds|
|
34
|
+
n = ::Sequel::Plugins::Temporal.now
|
35
|
+
ds.where{(created_at <= n) & ({expired_at=>nil} | (expired_at > n))}
|
36
|
+
end
|
37
|
+
master.def_dataset_method :with_current_version do
|
38
|
+
eager_graph(:current_version).where({:id.qualify(model.current_version_alias) => nil}.sql_negate)
|
39
|
+
end
|
40
|
+
version.many_to_one :master, class: master, key: :master_id
|
41
|
+
version.class_eval do
|
42
|
+
def current?
|
43
|
+
n = ::Sequel::Plugins::Temporal.now
|
44
|
+
!new? &&
|
45
|
+
created_at.to_time<=n &&
|
46
|
+
(expired_at.nil? || expired_at.to_time>n)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
unless opts[:delegate]==false
|
50
|
+
(version.columns-required-[:id]).each do |column|
|
51
|
+
master.class_eval <<-EOS
|
52
|
+
def #{column}
|
53
|
+
pending_or_current_version.#{column} if pending_or_current_version
|
54
|
+
end
|
55
|
+
EOS
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
module ClassMethods
|
60
|
+
attr_reader :version_class, :versions_alias, :current_version_alias
|
61
|
+
end
|
62
|
+
module DatasetMethods
|
63
|
+
end
|
64
|
+
module InstanceMethods
|
65
|
+
attr_reader :pending_version
|
66
|
+
|
67
|
+
def before_validation
|
68
|
+
prepare_pending_version
|
69
|
+
super
|
70
|
+
end
|
71
|
+
|
72
|
+
def validate
|
73
|
+
super
|
74
|
+
pending_version.errors.each do |key, key_errors|
|
75
|
+
key_errors.each{|error| errors.add key, error}
|
76
|
+
end if pending_version && !pending_version.valid?
|
77
|
+
end
|
78
|
+
|
79
|
+
def pending_or_current_version
|
80
|
+
pending_version || current_version
|
81
|
+
end
|
82
|
+
|
83
|
+
def attributes
|
84
|
+
if pending_version
|
85
|
+
pending_version.values
|
86
|
+
elsif current_version
|
87
|
+
current_version.values
|
88
|
+
else
|
89
|
+
{}
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def attributes=(attributes)
|
94
|
+
if !new? && attributes.delete(:partial_update) && current_version
|
95
|
+
current_attributes = current_version.keys.inject({}) do |hash, key|
|
96
|
+
hash[key] = current_version.send key
|
97
|
+
hash
|
98
|
+
end
|
99
|
+
attributes = current_attributes.merge attributes
|
100
|
+
end
|
101
|
+
attributes.delete :id
|
102
|
+
@pending_version ||= model.version_class.new
|
103
|
+
pending_version.set attributes
|
104
|
+
pending_version.master_id = id unless new?
|
105
|
+
end
|
106
|
+
|
107
|
+
def update_attributes(attributes={})
|
108
|
+
self.attributes = attributes
|
109
|
+
save raise_on_failure: false
|
110
|
+
end
|
111
|
+
|
112
|
+
def after_create
|
113
|
+
super
|
114
|
+
if pending_version
|
115
|
+
return false unless save_pending_version
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def before_update
|
120
|
+
if pending_version
|
121
|
+
expire_previous_version
|
122
|
+
return false unless save_pending_version
|
123
|
+
end
|
124
|
+
super
|
125
|
+
end
|
126
|
+
|
127
|
+
def destroy
|
128
|
+
versions_dataset.where(expired_at: nil).update expired_at: Time.now
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
|
133
|
+
def prepare_pending_version
|
134
|
+
return unless pending_version
|
135
|
+
pending_version.created_at = Time.now
|
136
|
+
end
|
137
|
+
|
138
|
+
def expire_previous_version
|
139
|
+
lock!
|
140
|
+
versions_dataset.where(expired_at: nil).update expired_at: pending_version.created_at
|
141
|
+
end
|
142
|
+
|
143
|
+
def save_pending_version
|
144
|
+
success = add_version pending_version
|
145
|
+
@pending_version = nil if success
|
146
|
+
success
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require "sequel/plugins/temporal"
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "sequel_temporal"
|
6
|
+
s.version = "0.1.0"
|
7
|
+
s.authors = ["Joseph HALTER", "Jonathan TRON"]
|
8
|
+
s.email = ["joseph.halter@thetalentbox.com", "jonathan.tron@thetalentbox.com"]
|
9
|
+
s.homepage = "https://github.com/TalentBox/sequel_temporal"
|
10
|
+
s.summary = "Temporal versioning for sequel."
|
11
|
+
s.description = "Temporal versioning for sequel, fully tested."
|
12
|
+
|
13
|
+
s.files = `git ls-files`.split("\n")
|
14
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
15
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
16
|
+
s.require_paths = ["lib"]
|
17
|
+
|
18
|
+
s.add_runtime_dependency "sequel", "~> 3.30.0"
|
19
|
+
|
20
|
+
s.add_development_dependency "sqlite3"
|
21
|
+
s.add_development_dependency "rspec", "~> 2.8.0.rc1"
|
22
|
+
s.add_development_dependency "timecop"
|
23
|
+
s.add_development_dependency "rake"
|
24
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
RSpec::Matchers.define :have_versions do |versions_str|
|
2
|
+
@table = have_versions_parse_table versions_str
|
3
|
+
@last_index = nil
|
4
|
+
@last_version = nil
|
5
|
+
match do |master|
|
6
|
+
versions = master.versions_dataset.order(:id).all
|
7
|
+
versions.size == @table.size && @table.each.with_index.all? do |version, index|
|
8
|
+
@last_index = index
|
9
|
+
@last_version = version
|
10
|
+
master_version = versions[index]
|
11
|
+
[:name, :price, :created_at, :expired_at, :current].all? do |column|
|
12
|
+
if column==:current
|
13
|
+
found = master_version.current?
|
14
|
+
expected = (version[column.to_s]=="true").to_s
|
15
|
+
else
|
16
|
+
found = master_version.send column
|
17
|
+
expected = version[column.to_s]
|
18
|
+
end
|
19
|
+
equal = found.to_s == expected
|
20
|
+
puts "#{column}: #{found} != #{expected}" unless equal
|
21
|
+
equal
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
failure_message_for_should do |master|
|
26
|
+
versions = master.versions_dataset.order(:id).all
|
27
|
+
if versions.size != @table.size
|
28
|
+
"Expected #{master.class} to have #{@table.size} versions but found #{versions.size}"
|
29
|
+
else
|
30
|
+
"Expected row #{@last_index+1} to match #{@last_version.inspect} but found #{versions[@last_index].inspect}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def have_versions_parse_table(str)
|
36
|
+
rows = str.strip.split("\n")
|
37
|
+
rows.collect!{|row| row[/^\s*\|(.+)\|\s*$/, 1].split("|").collect(&:strip)}
|
38
|
+
headers = rows.shift
|
39
|
+
rows.collect{|row| Hash[headers.zip row]}
|
40
|
+
end
|
@@ -0,0 +1,222 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "Sequel::Plugins::Temporal" do
|
4
|
+
before :all do
|
5
|
+
DB.drop_table(:room_versions) if DB.table_exists?(:room_versions)
|
6
|
+
DB.drop_table(:rooms) if DB.table_exists?(:rooms)
|
7
|
+
DB.create_table! :rooms do
|
8
|
+
primary_key :id
|
9
|
+
end
|
10
|
+
DB.create_table! :room_versions do
|
11
|
+
primary_key :id
|
12
|
+
foreign_key :master_id, :rooms
|
13
|
+
String :name
|
14
|
+
Fixnum :price
|
15
|
+
Date :created_at
|
16
|
+
Date :expired_at
|
17
|
+
end
|
18
|
+
@version_class = Class.new Sequel::Model do
|
19
|
+
set_dataset :room_versions
|
20
|
+
def validate
|
21
|
+
super
|
22
|
+
errors.add(:name, "is required") unless name
|
23
|
+
errors.add(:price, "is required") unless price
|
24
|
+
end
|
25
|
+
end
|
26
|
+
closure = @version_class
|
27
|
+
@master_class = Class.new Sequel::Model do
|
28
|
+
set_dataset :rooms
|
29
|
+
plugin :temporal, version_class: closure
|
30
|
+
end
|
31
|
+
end
|
32
|
+
before do
|
33
|
+
Timecop.freeze 2009, 11, 28
|
34
|
+
@version_class.truncate
|
35
|
+
@master_class.truncate
|
36
|
+
end
|
37
|
+
after do
|
38
|
+
Timecop.return
|
39
|
+
end
|
40
|
+
it "checks version class is given" do
|
41
|
+
lambda{
|
42
|
+
@version_class.plugin :temporal
|
43
|
+
}.should raise_error Sequel::Error, "please specify version class to use for temporal plugin"
|
44
|
+
end
|
45
|
+
it "checks required columns are present" do
|
46
|
+
lambda{
|
47
|
+
@version_class.plugin :temporal, version_class: @master_class
|
48
|
+
}.should raise_error Sequel::Error, "temporal plugin requires the following missing columns on version class: master_id, created_at, expired_at"
|
49
|
+
end
|
50
|
+
it "propagates errors from version to master" do
|
51
|
+
master = @master_class.new
|
52
|
+
master.should be_valid
|
53
|
+
master.attributes = {name: "Single Standard"}
|
54
|
+
master.should_not be_valid
|
55
|
+
master.errors.should == {price: ["is required"]}
|
56
|
+
end
|
57
|
+
it "#update_attributes returns false instead of raising errors" do
|
58
|
+
master = @master_class.new
|
59
|
+
master.update_attributes(name: "Single Standard").should be_false
|
60
|
+
master.should be_new
|
61
|
+
master.errors.should == {price: ["is required"]}
|
62
|
+
master.update_attributes(price: 98).should be_true
|
63
|
+
end
|
64
|
+
it "allows creating a master and its first version in one step" do
|
65
|
+
master = @master_class.new
|
66
|
+
master.update_attributes(name: "Single Standard", price: 98).should be_true
|
67
|
+
master.should_not be_new
|
68
|
+
master.should have_versions %Q{
|
69
|
+
| name | price | created_at | expired_at | current |
|
70
|
+
| Single Standard | 98 | 2009-11-28 | | true |
|
71
|
+
}
|
72
|
+
end
|
73
|
+
it "doesn't loose previous version in same-day update" do
|
74
|
+
master = @master_class.new
|
75
|
+
master.update_attributes name: "Single Standard", price: 98
|
76
|
+
master.update_attributes name: "Single Standard", price: 94
|
77
|
+
master.should have_versions %Q{
|
78
|
+
| name | price | created_at | expired_at | current |
|
79
|
+
| Single Standard | 98 | 2009-11-28 | 2009-11-28 | |
|
80
|
+
| Single Standard | 94 | 2009-11-28 | | true |
|
81
|
+
}
|
82
|
+
end
|
83
|
+
it "allows partial updating based on current version" do
|
84
|
+
master = @master_class.new
|
85
|
+
master.update_attributes name: "Single Standard", price: 98
|
86
|
+
master.update_attributes price: 94, partial_update: true
|
87
|
+
master.update_attributes name: "King Size", partial_update: true
|
88
|
+
master.should have_versions %Q{
|
89
|
+
| name | price | created_at | expired_at | current |
|
90
|
+
| Single Standard | 98 | 2009-11-28 | 2009-11-28 | |
|
91
|
+
| Single Standard | 94 | 2009-11-28 | 2009-11-28 | |
|
92
|
+
| King Size | 94 | 2009-11-28 | | true |
|
93
|
+
}
|
94
|
+
end
|
95
|
+
it "expires previous version but keep it in history" do
|
96
|
+
master = @master_class.new
|
97
|
+
master.update_attributes name: "Single Standard", price: 98
|
98
|
+
Timecop.freeze Date.today+1
|
99
|
+
master.update_attributes price: 94, partial_update: true
|
100
|
+
master.should have_versions %Q{
|
101
|
+
| name | price | created_at | expired_at | current |
|
102
|
+
| Single Standard | 98 | 2009-11-28 | 2009-11-29 | |
|
103
|
+
| Single Standard | 94 | 2009-11-29 | | true |
|
104
|
+
}
|
105
|
+
end
|
106
|
+
xit "doesn't do anything if unchanged" do
|
107
|
+
end
|
108
|
+
it "allows deleting current version" do
|
109
|
+
master = @master_class.new
|
110
|
+
master.update_attributes name: "Single Standard", price: 98
|
111
|
+
Timecop.freeze Date.today+1
|
112
|
+
master.destroy.should be_true
|
113
|
+
master.should have_versions %Q{
|
114
|
+
| name | price | created_at | expired_at | current |
|
115
|
+
| Single Standard | 98 | 2009-11-28 | 2009-11-29 | |
|
116
|
+
}
|
117
|
+
end
|
118
|
+
it "allows simultaneous updates without information loss" do
|
119
|
+
master = @master_class.new
|
120
|
+
master.update_attributes name: "Single Standard", price: 98
|
121
|
+
Timecop.freeze Date.today+1
|
122
|
+
master2 = @master_class.find id: master.id
|
123
|
+
master.update_attributes name: "Single Standard", price: 94
|
124
|
+
master2.update_attributes name: "Single Standard", price: 95
|
125
|
+
master.should have_versions %Q{
|
126
|
+
| name | price | created_at | expired_at | current |
|
127
|
+
| Single Standard | 98 | 2009-11-28 | 2009-11-29 | |
|
128
|
+
| Single Standard | 94 | 2009-11-29 | 2009-11-29 | |
|
129
|
+
| Single Standard | 95 | 2009-11-29 | | true |
|
130
|
+
}
|
131
|
+
end
|
132
|
+
it "allows simultaneous cumulative updates" do
|
133
|
+
master = @master_class.new
|
134
|
+
master.update_attributes name: "Single Standard", price: 98
|
135
|
+
Timecop.freeze Date.today+1
|
136
|
+
master2 = @master_class.find id: master.id
|
137
|
+
master.update_attributes price: 94, partial_update: true
|
138
|
+
master2.update_attributes name: "King Size", partial_update: true
|
139
|
+
master.should have_versions %Q{
|
140
|
+
| name | price | created_at | expired_at | current |
|
141
|
+
| Single Standard | 98 | 2009-11-28 | 2009-11-29 | |
|
142
|
+
| Single Standard | 94 | 2009-11-29 | 2009-11-29 | |
|
143
|
+
| King Size | 94 | 2009-11-29 | | true |
|
144
|
+
}
|
145
|
+
end
|
146
|
+
it "allows eager loading with conditions on current version" do
|
147
|
+
master = @master_class.new
|
148
|
+
master.update_attributes name: "Single Standard", price: 98
|
149
|
+
@master_class.eager_graph(:current_version).where("rooms_current_version.id IS NOT NULL").first.should be
|
150
|
+
Timecop.freeze Date.today+1
|
151
|
+
master.destroy
|
152
|
+
@master_class.eager_graph(:current_version).where("rooms_current_version.id IS NOT NULL").first.should be_nil
|
153
|
+
end
|
154
|
+
it "allows loading masters with a current version" do
|
155
|
+
master_destroyed = @master_class.new
|
156
|
+
master_destroyed.update_attributes name: "Single Standard", price: 98
|
157
|
+
master_destroyed.destroy
|
158
|
+
master_with_current = @master_class.new
|
159
|
+
master_with_current.update_attributes name: "Single Standard", price: 94
|
160
|
+
@master_class.with_current_version.all.should have(1).item
|
161
|
+
end
|
162
|
+
it "gets pending or current version attributes" do
|
163
|
+
master = @master_class.new
|
164
|
+
master.attributes.should == {}
|
165
|
+
master.pending_version.should be_nil
|
166
|
+
master.pending_or_current_version.should be_nil
|
167
|
+
master.update_attributes name: "Single Standard", price: 98
|
168
|
+
master.attributes[:name].should == "Single Standard"
|
169
|
+
master.pending_version.should be_nil
|
170
|
+
master.pending_or_current_version.name.should == "Single Standard"
|
171
|
+
master.attributes = {name: "King Size"}
|
172
|
+
master.attributes[:name].should == "King Size"
|
173
|
+
master.pending_version.should be
|
174
|
+
master.pending_or_current_version.name.should == "King Size"
|
175
|
+
end
|
176
|
+
it "allows to go back in time" do
|
177
|
+
master = @master_class.new
|
178
|
+
master.update_attributes name: "Single Standard", price: 98
|
179
|
+
Timecop.freeze Date.today+1
|
180
|
+
master.update_attributes price: 94, partial_update: true
|
181
|
+
master.should have_versions %Q{
|
182
|
+
| name | price | created_at | expired_at | current |
|
183
|
+
| Single Standard | 98 | 2009-11-28 | 2009-11-29 | |
|
184
|
+
| Single Standard | 94 | 2009-11-29 | | true |
|
185
|
+
}
|
186
|
+
master.current_version.price.should == 94
|
187
|
+
Sequel::Plugins::Temporal.at(Date.today-1) do
|
188
|
+
master.current_version(true).price.should == 98
|
189
|
+
end
|
190
|
+
end
|
191
|
+
it "delegates attributes from master to pending_or_current_version" do
|
192
|
+
master = @master_class.new
|
193
|
+
master.name.should be_nil
|
194
|
+
master.update_attributes name: "Single Standard", price: 98
|
195
|
+
master.name.should == "Single Standard"
|
196
|
+
master.attributes = {name: "King Size", partial_update: true}
|
197
|
+
master.name.should == "King Size"
|
198
|
+
end
|
199
|
+
it "avoids delegation with option delegate: false" do
|
200
|
+
closure = @version_class
|
201
|
+
without_delegation_class = Class.new Sequel::Model do
|
202
|
+
set_dataset :rooms
|
203
|
+
plugin :temporal, version_class: closure, delegate: false
|
204
|
+
end
|
205
|
+
master = without_delegation_class.new
|
206
|
+
expect{ master.name }.to raise_error NoMethodError
|
207
|
+
end
|
208
|
+
it "get current_version association name from class name" do
|
209
|
+
class MyNameVersion < Sequel::Model
|
210
|
+
set_dataset :room_versions
|
211
|
+
end
|
212
|
+
class MyName < Sequel::Model
|
213
|
+
set_dataset :rooms
|
214
|
+
plugin :temporal, version_class: MyNameVersion
|
215
|
+
end
|
216
|
+
expect do
|
217
|
+
MyName.eager_graph(:current_version).where("my_name_current_version.id IS NOT NULL").first
|
218
|
+
end.not_to raise_error
|
219
|
+
Object.send :remove_const, :MyName
|
220
|
+
Object.send :remove_const, :MyNameVersion
|
221
|
+
end
|
222
|
+
end
|
metadata
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sequel_temporal
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Joseph HALTER
|
9
|
+
- Jonathan TRON
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2011-12-08 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: sequel
|
17
|
+
requirement: &2151890200 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ~>
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 3.30.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *2151890200
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: sqlite3
|
28
|
+
requirement: &2151889020 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *2151889020
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: rspec
|
39
|
+
requirement: &2151887200 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ~>
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: 2.8.0.rc1
|
45
|
+
type: :development
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: *2151887200
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: timecop
|
50
|
+
requirement: &2151902600 !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
type: :development
|
57
|
+
prerelease: false
|
58
|
+
version_requirements: *2151902600
|
59
|
+
- !ruby/object:Gem::Dependency
|
60
|
+
name: rake
|
61
|
+
requirement: &2151901800 !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
type: :development
|
68
|
+
prerelease: false
|
69
|
+
version_requirements: *2151901800
|
70
|
+
description: Temporal versioning for sequel, fully tested.
|
71
|
+
email:
|
72
|
+
- joseph.halter@thetalentbox.com
|
73
|
+
- jonathan.tron@thetalentbox.com
|
74
|
+
executables: []
|
75
|
+
extensions: []
|
76
|
+
extra_rdoc_files: []
|
77
|
+
files:
|
78
|
+
- .gitignore
|
79
|
+
- .travis.yml
|
80
|
+
- Gemfile
|
81
|
+
- README.md
|
82
|
+
- Rakefile
|
83
|
+
- lib/sequel/plugins/temporal.rb
|
84
|
+
- lib/sequel_temporal.rb
|
85
|
+
- sequel_temporal.gemspec
|
86
|
+
- spec/spec_helper.rb
|
87
|
+
- spec/support/temporal_matchers.rb
|
88
|
+
- spec/temporal_spec.rb
|
89
|
+
homepage: https://github.com/TalentBox/sequel_temporal
|
90
|
+
licenses: []
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
none: false
|
97
|
+
requirements:
|
98
|
+
- - ! '>='
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
segments:
|
102
|
+
- 0
|
103
|
+
hash: -1369786071214787930
|
104
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
segments:
|
111
|
+
- 0
|
112
|
+
hash: -1369786071214787930
|
113
|
+
requirements: []
|
114
|
+
rubyforge_project:
|
115
|
+
rubygems_version: 1.8.10
|
116
|
+
signing_key:
|
117
|
+
specification_version: 3
|
118
|
+
summary: Temporal versioning for sequel.
|
119
|
+
test_files:
|
120
|
+
- spec/spec_helper.rb
|
121
|
+
- spec/support/temporal_matchers.rb
|
122
|
+
- spec/temporal_spec.rb
|