Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Additional specs. We're now at 100% coverage. Removed examples from s…

…equel core.
  • Loading branch information...
commit 65a863f884f7060cf8f5e3aa80bf8f3a52eb6bf7 1 parent 18a6a5e
@ciconia ciconia authored
View
4 model/CHANGELOG
@@ -1,5 +1,9 @@
=== SVN
+* Removed examples from sequel core.
+
+* Additional specs. We're now at 100% coverage.
+
* Refactored hooks code. Hooks are now inheritable, and can be defined by supplying a block or a method name, or by overriding the hook instance method. Hook chains can now be broken by returning false (#111, #112).
=== 0.1 (2007-12-30)
View
30 model/examples/basic.rb
@@ -1,30 +0,0 @@
-require 'rubygems'
-require 'sequel/sqlite'
-
-# Let's open an in-memory database
-DB = Sequel.open 'sqlite:/'
-
-# Create a new table
-DB.create_table :items do
- primary_key :id, :integer, :auto_increment => true
- column :name, :text
- column :price, :float
-end
-
-# Create a dataset
-items = DB[:items]
-
-# Populate the table
-items << {:name => 'abc', :price => rand * 100}
-items << {:name => 'def', :price => rand * 100}
-items << {:name => 'ghi', :price => rand * 100}
-
-# Print out the number of records
-puts "Item count: #{items.count}"
-
-# Print out the records
-items.print(:name, :price)
-
-# Print out the average price
-puts "The average price is: #{items.avg(:price)}"
-
View
23 model/examples/countries.rb
@@ -1,23 +0,0 @@
-require 'sequel/sqlite'
-
-DB = Sequel.open 'sqlite:///countries.db'
-countries = DB[:countries]
-
-# select name, region and popuplation
-countries.select(:name, :region, :population).all
-
-# show the name for the countries that have a population of
-# at least 200 million.
-large_populations = countries.filter {population >= 200_000_000}
-large_populations.map(:name)
-
-# Give the name and the per capita GDP for those countries
-# with a population of at least 200 million.
-large_populations.hash_map(:name, :gdp)
-
-# Show the name and population in millions for the countries of Asia
-countries.filter(:region => 'Asia').select(:name, 'population/1000000').all
-
-# Show the name and population for France, Germany, Italy
-countries.filter(:name => ['France', 'Germany', 'Italy']).hash_map(:name, :population)
-
View
16 model/examples/csv.rb
@@ -1,16 +0,0 @@
-require 'rubygems'
-require 'faster_csv'
-require File.join(File.dirname(__FILE__), '../lib/sequel/sqlite')
-
-DB = Sequel.open 'sqlite:///test.db'
-DB.create_table :countries do
- column :name, :text
- column :population, :integer
-end unless DB.table_exists?(:countries)
-
-FCSV.foreach('/home/sharon/reality/server/trunk/test.csv',
- :headers => true, :header_converters => :symbol) do |l|
- DB[:countries] << l.to_hash
-end
-
-DB[:countries].print(:name, :population)
View
30 model/examples/filters.rb
@@ -1,30 +0,0 @@
-require 'rubygems'
-require 'sequel/sqlite' # gem install sequel (and sqlite3 as well)
-
-DB = Sequel.open 'sqlite:/' # memory DB
-
-DB.create_table :items do
- text :name
- decimal :price
-end
-
-items = DB[:items]
-
-1000.times {|i| items << {:name => "item#{i}", :price => rand * 100}}
-
-puts "#{items.count} total items"
-
-puts "Average price: #{items.avg(:price)}"
-
-puts "3 most expensive items:"
-items.order(:price.DESC).limit(3).print(:name, :price)
-
-puts "#{items.filter {price < items.avg(:price)}.count} below the average"
-#{}
-
-puts "Changing price for expensive items"
-items.filter {price > items.avg(:price)}.update(:price => 'price + 10'.expr)
-
-puts "Highest price: #{items.max(:price)}"
-
-puts "Updated average price: #{items.avg(:price)}"
View
40 model/examples/view.rb
@@ -1,40 +0,0 @@
-require 'rubygems'
-require File.join(File.dirname(__FILE__), '../lib/sequel/sqlite')
-
-db = Sequel.open("sqlite:/:memory:")
-db << "create table k1 (id integer primary key autoincrement, f1 text)"
-db << "create table k2 (id integer primary key autoincrement, f2 text)"
-db << "create table k3 (id integer primary key autoincrement, f3 text)"
-db << "create table records (id integer primary key autoincrement,
- k1_id integer, k2_id integer, k3_id integer, value text)"
-db << "create unique index records_key_unique on records(k1_id,k2_id,k3_id)"
-db << "create view data as select records.id as id, k1.f1 as f1, k2.f2 as f2,
- k3.f3 as f3, records.value as value
- from records inner join k1 on records.k1_id = k1.id
- inner join k2 on records.k2_id = k2.id
- inner join k3 on records.k3_id = k3.id
- order by k1.f1, k2.f2, k3.f3"
-k1 = db[:k1]
-k1 << [1, 'Alfred']
-k1 << [2,'Barry']
-k1 << [3, 'Charles']
-k1 << [4,'Dave']
-k1 << [5,'Douglas']
-k2 = db[:k2]
-k2 << [1,'USA']
-k2 << [2,'Japan']
-k2 << [3,'Brazil']
-k3 = db[:k3]
-k3 << [1,'APL']
-k3 << [2,'BASIC']
-k3 << [3,'COBOL']
-k3 << [4,'Ruby']
-records = db[:records]
-records << [1,1,1,1,'Red']
-records << [2,2,2,2,'Yellow']
-records << [3,3,3,3,'Green']
-records << [4,4,1,4,'Magenta']
-records << [5,5,2,4,'Blue']
-data = db[:data].filter(:f1 => ['Dave','Douglas'])
-puts data.sql
-data.print(:id, :f1, :f2, :f3, :value)
View
4 model/lib/sequel_model/base.rb
@@ -19,8 +19,8 @@ def self.database_opened(db)
# Returns the dataset associated with the Model class.
def self.dataset
- @dataset || super_dataset or
- raise Error, "No dataset associated with #{self}"
+ (@dataset ||= super_dataset) ||
+ (raise Error, "No dataset associated with #{self}")
end
def self.super_dataset # :nodoc:
View
42 model/lib/sequel_model/hooks.rb
@@ -12,37 +12,29 @@ class Model
:after_destroy
]
- def self.def_hook_method(m) #:nodoc:
- # write hook def
- hook_def = "
- def self.#{m}(method = nil, &block)
- unless block
- (raise SequelError, 'No hook method specified') unless method
- block = proc {send method}
- end
- add_hook(#{m.inspect}, &block)
+ # Some fancy code generation here in order to define the hook class methods...
+ HOOK_METHOD_STR = %Q{
+ def self.%s(method = nil, &block)
+ unless block
+ (raise SequelError, 'No hook method specified') unless method
+ block = proc {send method}
end
- "
-
- instance_eval(hook_def)
+ add_hook(%s, &block)
+ end
+ }
+
+ def self.def_hook_method(m) #:nodoc:
+ instance_eval(HOOK_METHOD_STR % [m.to_s, m.inspect])
end
HOOKS.each {|h| define_method(h) {}}
HOOKS.each {|h| def_hook_method(h)}
# Returns the hooks hash for the model class.
- def self.hooks
+ def self.hooks #:nodoc:
@hooks ||= Hash.new {|h, k| h[k] = []}
end
- # Returns true if the model class or any of its ancestors have defined
- # hooks for the given hook key. Notice that this method cannot detect
- # hooks defined using overridden methods.
- def self.has_hooks?(key)
- has = hooks[key] && !hooks[key].empty?
- has || ((self != Model) && superclass.has_hooks?(key))
- end
-
def self.add_hook(hook, &block) #:nodoc:
chain = hooks[hook]
chain << block
@@ -51,5 +43,13 @@ def self.add_hook(hook, &block) #:nodoc:
chain.each {|h| break false if instance_eval(&h) == false}
end
end
+
+ # Returns true if the model class or any of its ancestors have defined
+ # hooks for the given hook key. Notice that this method cannot detect
+ # hooks defined using overridden methods.
+ def self.has_hooks?(key)
+ has = hooks[key] && !hooks[key].empty?
+ has || ((self != Model) && superclass.has_hooks?(key))
+ end
end
end
View
3  model/lib/sequel_model/plugins.rb
@@ -19,6 +19,9 @@ def is(plugin, *args)
metaclass.send(:include, m::ClassMethods)
end
if m.const_defined?("DatasetMethods")
+ unless @dataset
+ raise Sequel::Error, "Plugin cannot be applied because the model class has no dataset"
+ end
dataset.meta_def(:"#{plugin}_opts") {args.first}
dataset.metaclass.send(:include, m::DatasetMethods)
end
View
4 model/lib/sequel_model/schema.rb
@@ -5,7 +5,9 @@ class Model
# This is only needed if you want to use the create_table or drop_table
# methods.
def self.set_schema(name = nil, &block)
- name ? set_dataset(db[name]) : name = table_name
+ if name
+ set_dataset(db[name])
+ end
@schema = Schema::Generator.new(db, &block)
if @schema.primary_key_name
set_primary_key @schema.primary_key_name
View
23 model/spec/hooks_spec.rb
@@ -244,3 +244,26 @@ def delete
]
end
end
+
+describe "Model#has_hooks?" do
+ setup do
+ @c = Class.new(Sequel::Model)
+ end
+
+ specify "should return false if no hooks are defined" do
+ @c.has_hooks?(:before_save).should be_false
+ end
+
+ specify "should return true if hooks are defined" do
+ @c.before_save {'blah'}
+ @c.has_hooks?(:before_save).should be_true
+ end
+
+ specify "should return true if hooks are inherited" do
+ @d = Class.new(@c)
+ @d.has_hooks?(:before_save).should be_false
+
+ @c.before_save :blah
+ @d.has_hooks?(:before_save).should be_true
+ end
+end
View
23 model/spec/plugins_spec.rb
@@ -6,6 +6,8 @@ module Timestamped
def self.apply(m, opts)
m.class_def(:get_stamp) {@values[:stamp]}
m.meta_def(:stamp_opts) {opts}
+ puts "opts: #{opts.inspect}"
+ puts "stamp_opts: #{m.stamp_opts.inspect}"
m.before_save {@values[:stamp] = Time.now}
end
@@ -17,10 +19,9 @@ module ClassMethods
def deff; timestamped_opts; end
end
- # ??
- # module DatasetMethods
- # def ghi; timestamped_opts; end
- # end
+ module DatasetMethods
+ def ghi; timestamped_opts; end
+ end
end
end
@@ -39,6 +40,7 @@ def deff; timestamped_opts; end
c = nil
proc do
c = Class.new(Sequel::Model) do
+ set_dataset MODEL_DB[:items]
is :timestamped, :a => 1, :b => 2
end
end.should_not raise_error(LoadError)
@@ -46,6 +48,7 @@ def deff; timestamped_opts; end
c.should respond_to(:stamp_opts)
c.stamp_opts.should == {:a => 1, :b => 2}
+ # instance methods
m = c.new
m.should respond_to(:get_stamp)
m.should respond_to(:abc)
@@ -54,8 +57,20 @@ def deff; timestamped_opts; end
m[:stamp] = t
m.get_stamp.should == t
+ # class methods
c.should respond_to(:deff)
c.deff.should == {:a => 1, :b => 2}
+
+ # dataset methods
+ c.dataset.should respond_to(:ghi)
+ c.dataset.ghi.should == {:a => 1, :b => 2}
end
+ it "should fail to apply if the plugin has DatasetMethod and the model has no datset" do
+ proc do
+ Class.new(Sequel::Model) do
+ is :timestamped, :a => 1, :b => 2
+ end
+ end.should raise_error(Sequel::Error)
+ end
end
View
83 model/spec/record_spec.rb
@@ -217,7 +217,6 @@ def columns
end
describe "Model#pk" do
-
before(:each) do
@m = Class.new(Sequel::Model)
end
@@ -248,7 +247,23 @@ def columns
m = @m.new(:id => 111, :x => 2, :y => 3)
proc {m.pk}.should raise_error(Sequel::Error)
end
+end
+
+describe "Model#pkey" do # deprecated
+ before(:each) do
+ @m = Class.new(Sequel::Model)
+ end
+ it "should by default return the value of the :id column" do
+ m = @m.new(:id => 111, :x => 2, :y => 3)
+ m.pkey.should == 111
+ end
+
+ it "should be return the primary key value for custom primary key" do
+ @m.set_primary_key :x
+ m = @m.new(:id => 111, :x => 2, :y => 3)
+ m.pkey.should == 2
+ end
end
describe "Model#pk_hash" do
@@ -345,18 +360,70 @@ def self.columns; [:x, :y]; end
end
describe Sequel::Model, "#exists?" do
-
before(:each) do
@model = Class.new(Sequel::Model(:items))
- @model_a = @model.new
+ @m = @model.new
+ end
+
+ it "should returns true when #this.count > 0" do
+ @m.this.meta_def(:count) {1}
+ @m.exists?.should be_true
+ end
+
+ it "should return false when #this.count == 0" do
+ @m.this.meta_def(:count) {0}
+ @m.exists?.should be_false
+ end
+end
+
+describe Sequel::Model, "#each" do
+ setup do
+ @model = Class.new(Sequel::Model(:items))
+ @m = @model.new(:a => 1, :b => 2, :id => 4444)
+ end
+
+ specify "should iterate over the values" do
+ h = {}
+ @m.each {|k, v| h[k] = v}
+ h.should == {:a => 1, :b => 2, :id => 4444}
+ end
+end
+
+describe Sequel::Model, "#keys" do
+ setup do
+ @model = Class.new(Sequel::Model(:items))
+ @m = @model.new(:a => 1, :b => 2, :id => 4444)
end
+
+ specify "should return the value keys" do
+ @m.keys.size.should == 3
+ @m.keys.should include(:a, :b, :id)
+
+ @m = @model.new()
+ @m.keys.should == []
+ end
+end
- it "should returns true when current instance exists" do
- @model_a.exists?.should be_true
+describe Sequel::Model, "#===" do
+ specify "should compare instances by values" do
+ a = Sequel::Model.new(:id => 1, :x => 3)
+ b = Sequel::Model.new(:id => 1, :x => 4)
+ c = Sequel::Model.new(:id => 1, :x => 3)
+
+ a.should_not == b
+ a.should == c
+ b.should_not == c
end
+end
- it "should return false when the current instance does not exist" do
- pending("how would this be false?")
+describe Sequel::Model, "#===" do
+ specify "should compare instances by pk only" do
+ a = Sequel::Model.new(:id => 1, :x => 3)
+ b = Sequel::Model.new(:id => 1, :x => 4)
+ c = Sequel::Model.new(:id => 2, :x => 3)
+
+ a.should === b
+ a.should_not === c
end
+end
-end
View
28 model/spec/relations_spec.rb
@@ -38,6 +38,16 @@ def update(values)
$sqls.should == ["SELECT * FROM nodes WHERE (id = 234) LIMIT 1"]
end
+ it "should accept deprecated class option" do
+ @c2.one_to_one :parent, :class => MODEL_DB[:xyz]
+
+ d = @c2.new(:id => 1, :parent_id => 789)
+ p = d.parent
+ p.class.should == Hash
+
+ MODEL_DB.sqls.should == ["SELECT * FROM xyz WHERE (id = 789) LIMIT 1"]
+ end
+
it "should use explicit key if given" do
@c2.one_to_one :parent, :from => @c2, :key => :blah
@@ -120,6 +130,24 @@ def update(values)
a.should be_a_kind_of(Sequel::Dataset)
a.sql.should == 'SELECT * FROM attributes WHERE (node_id = 1234)'
end
+
+ it "should accept deprecated class option" do
+ @c2.one_to_many :attributes, :class => MODEL_DB[:xyz], :key => :node_id
+
+ n = @c2.new(:id => 1234)
+ a = n.attributes
+ a.should be_a_kind_of(Sequel::Dataset)
+ a.sql.should == 'SELECT * FROM xyz WHERE (node_id = 1234)'
+ end
+
+ it "should accept deprecated on option" do
+ @c2.one_to_many :attributes, :from => MODEL_DB[:xyz], :on => :node_id
+
+ n = @c2.new(:id => 1234)
+ a = n.attributes
+ a.should be_a_kind_of(Sequel::Dataset)
+ a.sql.should == 'SELECT * FROM xyz WHERE (node_id = 1234)'
+ end
it "should support plain dataset in the from option" do
@c2.one_to_many :attributes, :from => MODEL_DB[:xyz], :key => :node_id
View
14 model/spec/schema_spec.rb
@@ -19,16 +19,18 @@
before(:each) do
MODEL_DB.reset
- @model = Class.new(Sequel::Model(:items))
+ @model = Class.new(Sequel::Model) do
+ set_dataset MODEL_DB[:items]
+ set_schema do
+ text :name
+ float :price, :null => false
+ end
+ end
end
it "should get the create table SQL list from the db and execute it line by line" do
- #db.create_table_sql_list(table_name, *schema.create_info).each {|s| db << s}
- @model.should_receive(:table_name).and_return(:items)
- @model.schema.should_receive(:create_info)
- @model.db.should_receive(:create_table_sql_list)
- pending("Finish specing this")
@model.create_table
+ MODEL_DB.sqls.should == ['CREATE TABLE items (name text, price float NOT NULL)']
end
end
Please sign in to comment.
Something went wrong with that request. Please try again.