dm-spec 0.9.10
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/LICENSE +20 -0
- data/README.textile +35 -0
- data/Rakefile +54 -0
- data/TODO +133 -0
- data/dm-spec.gemspec +23 -0
- data/lib/dm-spec.rb +5 -0
- data/lib/spec/matchers/dm/belongs_to.rb +42 -0
- data/lib/spec/matchers/dm/has_and_belongs_to_many.rb +38 -0
- data/lib/spec/matchers/dm/has_many.rb +48 -0
- data/lib/spec/matchers/dm/has_property.rb +35 -0
- data/lib/spec/matchers/dm/has_timestamps.rb +55 -0
- data/spec/dm/belongs_to_spec.rb +28 -0
- data/spec/dm/has_and_belongs_to_many_spec.rb +29 -0
- data/spec/dm/has_many_spec.rb +0 -0
- data/spec/dm/has_property_spec.rb +0 -0
- data/spec/dm/has_timestamps_spec.rb +28 -0
- data/spec/spec.opts +5 -0
- data/spec/spec_helper.rb +108 -0
- metadata +80 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Jakub Stastny aka Botanicus
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.textile
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
h1. About
|
2
|
+
|
3
|
+
RSpec matchers for DataMapper.
|
4
|
+
|
5
|
+
h1. Usage
|
6
|
+
|
7
|
+
You must include DataMapperMatchers to your specs. It can be done in *spec/spec_helper.rb*:
|
8
|
+
|
9
|
+
<pre>
|
10
|
+
$: << File.dirname(__FILE__) + "/../lib"
|
11
|
+
require "dm-core"
|
12
|
+
require "dm-spec"
|
13
|
+
|
14
|
+
DataMapper.setup(:default, "sqlite3::memory")
|
15
|
+
|
16
|
+
Spec::Runner.configure do |config|
|
17
|
+
config.include(DataMapperMatchers)
|
18
|
+
config.before(:each) do
|
19
|
+
DataMapper.auto_migrate!
|
20
|
+
end
|
21
|
+
end
|
22
|
+
</pre>
|
23
|
+
|
24
|
+
That's it. Now just use these matchers in your specs. All the matchers you should call on model class, not on model instance.
|
25
|
+
|
26
|
+
<pre>
|
27
|
+
Post.should has_property(:title)
|
28
|
+
Post.should has_many(:comments)
|
29
|
+
Post.should has_and_belongs_to_many(:tags)
|
30
|
+
Post.should belongs_to(:category)
|
31
|
+
Post.should has_timestamps # created_at, updated_at
|
32
|
+
Post.should has_timestamps(:at) # created_at, updated_at
|
33
|
+
Post.should has_timestamps(:on) # created_on, updated_on
|
34
|
+
Post.should has_timestamps(:created_at)
|
35
|
+
</pre>
|
data/Rakefile
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
|
4
|
+
GEM_NAME = "dm-spec"
|
5
|
+
AUTHOR = "Jakub Stastny aka Botanicus"
|
6
|
+
EMAIL = "knava.bestvinensis@gmail.com"
|
7
|
+
HOMEPAGE = "http://101Ideas.cz/"
|
8
|
+
SUMMARY = "RSpec matchers for DataMapper."
|
9
|
+
GEM_VERSION = "0.9.10"
|
10
|
+
|
11
|
+
spec = Gem::Specification.new do |s|
|
12
|
+
s.name = GEM_NAME
|
13
|
+
s.version = GEM_VERSION
|
14
|
+
s.platform = Gem::Platform::RUBY
|
15
|
+
s.has_rdoc = true
|
16
|
+
s.extra_rdoc_files = ["README.textile", "LICENSE"]
|
17
|
+
s.summary = SUMMARY
|
18
|
+
s.description = s.summary
|
19
|
+
s.author = AUTHOR
|
20
|
+
s.email = EMAIL
|
21
|
+
s.homepage = HOMEPAGE
|
22
|
+
s.require_path = 'lib'
|
23
|
+
s.files = %w(LICENSE README.textile Rakefile) + Dir.glob("{lib,spec,app,public,stubs}/**/*")
|
24
|
+
end
|
25
|
+
|
26
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
27
|
+
pkg.gem_spec = spec
|
28
|
+
end
|
29
|
+
|
30
|
+
desc "Create a gemspec file"
|
31
|
+
task :gemspec do
|
32
|
+
File.open("#{GEM_NAME}.gemspec", "w") do |file|
|
33
|
+
file.puts spec.to_ruby
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def sudo_gem(cmd)
|
38
|
+
sh "#{SUDO} #{RUBY} -S gem #{cmd}", :verbose => false
|
39
|
+
end
|
40
|
+
|
41
|
+
desc "Install #{GEM_NAME} #{GEM_VERSION}"
|
42
|
+
task :install => [ :package ] do
|
43
|
+
sudo_gem "install --local pkg/#{GEM_NAME}-#{GEM_VERSION} --no-update-sources"
|
44
|
+
end
|
45
|
+
|
46
|
+
desc "Uninstall #{GEM_NAME} #{GEM_VERSION}"
|
47
|
+
task :uninstall => [ :clobber ] do
|
48
|
+
sudo_gem "uninstall #{GEM_NAME} -v#{GEM_VERSION} -Ix"
|
49
|
+
end
|
50
|
+
|
51
|
+
require 'spec/rake/spectask'
|
52
|
+
desc 'Default: run spec examples'
|
53
|
+
task :default => 'spec'
|
54
|
+
|
data/TODO
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
- check property options
|
2
|
+
- more flexible way for checking associations
|
3
|
+
|
4
|
+
be_timestamped
|
5
|
+
be_key
|
6
|
+
validace
|
7
|
+
Category.should # => Expectation
|
8
|
+
Category.should has_property(:name) # => true
|
9
|
+
Category.my_property.should be_private
|
10
|
+
... soo ...
|
11
|
+
should true => OK
|
12
|
+
=> just return self instead of true => chain
|
13
|
+
@category.should has(1).error_on(:name).with("Nazev...")
|
14
|
+
|
15
|
+
irb(main):012:0> Product.slug
|
16
|
+
=> #<Property:Product:slug>
|
17
|
+
irb(main):014:0> Product.slug.to_yaml_properties
|
18
|
+
=> ["@custom", "@default", "@extra_options", "@field", "@fields", "@getter", "@index", "@instance_variable_name", "@key", "@lazy", "@length", "@model", "@name", "@nullable", "@options", "@primitive", "@reader_visibility", "@serial", "@track", "@type", "@unique_index", "@writer_visibility"]
|
19
|
+
irb(main):015:0> Product.slug.key?
|
20
|
+
=> true
|
21
|
+
irb(main):018:0> Product.slug.serial?
|
22
|
+
=> false
|
23
|
+
irb(main):019:0> Product.slug.default
|
24
|
+
=> nil
|
25
|
+
irb(main):022:0> Product.slug.extra_options
|
26
|
+
=> {:writter=>:private}
|
27
|
+
irb(main):027:0> Product.slug.unique_index
|
28
|
+
=> false
|
29
|
+
rb(main):030:0> Product.slug.reader_visibility
|
30
|
+
=> :public
|
31
|
+
irb(main):032:0> Product.slug.options
|
32
|
+
=> {:key=>true, :nullable=>false, :auto_validation=>false}
|
33
|
+
irb(main):004:0> Product.slug.nullable?
|
34
|
+
=> false
|
35
|
+
irb(main):006:0> Product.slug.args_and_options
|
36
|
+
=> [[], {}]
|
37
|
+
irb(main):007:0> Product.slug.blank?
|
38
|
+
=> false
|
39
|
+
irb(main):008:0> Product.slug.present?
|
40
|
+
=> true
|
41
|
+
irb(main):009:0> Product.slug.index
|
42
|
+
=> false
|
43
|
+
irb(main):010:0> Product.slug.size
|
44
|
+
=> 50
|
45
|
+
irb(main):011:0> Product.slug.primitive
|
46
|
+
=> String
|
47
|
+
irb(main):012:0> Product.slug.unique
|
48
|
+
=> true
|
49
|
+
|
50
|
+
|
51
|
+
irb(main):022:0> OrderItem.field_naming_convention
|
52
|
+
NameError: undefined local variable or method `args' for DataMapper:Module
|
53
|
+
irb(main):023:0> OrderItem.to_yaml_properties
|
54
|
+
=> ["@_valid_relations", "@field_naming_conventions", "@properties", "@relationships", "@storage_names", "@validations"]
|
55
|
+
irb(main):024:0> OrderItem.eager_properties
|
56
|
+
=> [#<Property:OrderItem:id>, #<Property:OrderItem:inverted>, #<Property:OrderItem:count>, #<Property:OrderItem:size>, #<Property:OrderItem:color>, #<Property:OrderItem:unit_price>, #<Property:OrderItem:product_slug>, #<Property:OrderItem:order_variable_symbol>, #<Property:OrderItem:color_id>, #<Property:OrderItem:size_height>, #<Property:OrderItem:size_width>]
|
57
|
+
irb(main):025:0> OrderItem.opts_from_validator_args
|
58
|
+
ArgumentError: wrong number of arguments (0 for 1)
|
59
|
+
irb(main):026:0> OrderItem.registered_as_hook?
|
60
|
+
ArgumentError: wrong number of arguments (0 for 2)
|
61
|
+
irb(main):027:0> OrderItem.first_or_create
|
62
|
+
ArgumentError: wrong number of arguments (0 for 1)
|
63
|
+
irb(main):028:0> OrderItem.property :count
|
64
|
+
ArgumentError: wrong number of arguments (1 for 2)
|
65
|
+
irb(main):029:0> OrderItem.hook_method_name
|
66
|
+
ArgumentError: wrong number of arguments (0 for 3)
|
67
|
+
irb(main):030:0> cattr_reader
|
68
|
+
NameError: undefined local variable or method `cattr_reader' for #<Object:0xb7d1894c>
|
69
|
+
irb(main):031:0> OrderItem.properties_with_subclasses
|
70
|
+
=> #<PropertySet:{#<Property:OrderItem:id>,#<Property:OrderItem:inverted>,#<Property:OrderItem:count>,#<Property:OrderItem:size>,#<Property:OrderItem:color>,#<Property:OrderItem:unit_price>,#<Property:OrderItem:product_slug>,#<Property:OrderItem:order_variable_symbol>,#<Property:OrderItem:color_id>,#<Property:OrderItem:size_height>,#<Property:OrderItem:size_width>}>
|
71
|
+
irb(main):032:0> OrderItem.timestamps
|
72
|
+
ArgumentError: You need to pass at least one argument
|
73
|
+
irb(main):033:0> OrderItem.relationships
|
74
|
+
=> {:product=>#<DataMapper::Associations::Relationship:0xb6cd62c8 @repository_name=:default, @parent_model=Product, @parent_properties=nil, @name=:product, @child_key=#<PropertySet:{#<Property:OrderItem:product_slug>}>, @child_model=OrderItem, @parent_key=#<PropertySet:{#<Property:Product:slug>}>, @options={}, @query={}, @child_properties=nil>, :order=>#<DataMapper::Associations::Relationship:0xb6cd7268 @repository_name=:default, @parent_model=Order, @parent_properties=nil, @name=:order, @child_key=#<PropertySet:{#<Property:OrderItem:order_variable_symbol>}>, @child_model=OrderItem, @parent_key=#<PropertySet:{#<Property:Order:variable_symbol>}>, @options={}, @query={}, @child_properties=nil>, :color=>#<DataMapper::Associations::Relationship:0xb6cd5350 @repository_name=:default, @parent_model=Color, @parent_properties=nil, @name=:color, @child_key=#<PropertySet:{#<Property:OrderItem:color_id>}>, @child_model=OrderItem, @parent_key=#<PropertySet:{#<Property:Color:id>}>, @options={}, @query={}, @child_properties=nil>}
|
75
|
+
irb(main):034:0> OrderItem.name
|
76
|
+
=> "OrderItem"
|
77
|
+
irb(main):035:0> OrderItem.validatable?
|
78
|
+
=> false
|
79
|
+
irb(main):036:0> OrderItem.default_order
|
80
|
+
=> [#<DataMapper::Query::Direction #<Property:OrderItem:id> asc>]
|
81
|
+
irb(main):037:0> OrderItem.class_variables
|
82
|
+
=> []
|
83
|
+
irb(main):038:0> OrderItem.base_model
|
84
|
+
=> OrderItem
|
85
|
+
irb(main):039:0> OrderItem.default_scope
|
86
|
+
=> {}
|
87
|
+
irb(main):040:0> OrderItem.ancestors
|
88
|
+
=> [OrderItem, DataMapper::Validate, DataMapper::Timestamp, #<Module:0xb6cdf0f8>, #<Module:0xb6ce00ac>, #<Module:0xb6ce0f98>, #<Module:0xb6ce1e48>, Extlib::Hook, DataMapper::Hook, DataMapper::Resource, DataMapper::Types, DataMapper::Resource::Transaction, DataMapper::Assertions, Object, Spec::Extensions::Main, Spec::Expectations::ObjectExpectations, DataMapper::Sweatshop::Unique, Base64::Deprecated, Base64, JSON::Ext::Generator::GeneratorMethods::Object, Kernel]
|
89
|
+
irb(main):041:0> OrderItem.generate_attributes
|
90
|
+
DataMapper::Sweatshop::NoFixtureExist: default fixture was not found for class OrderItem
|
91
|
+
irb(main):042:0> OrderItem.paranoid_properties
|
92
|
+
=> {}
|
93
|
+
irb(main):043:0> OrderItem.make
|
94
|
+
DataMapper::Sweatshop::NoFixtureExist: default fixture was not found for class OrderItem
|
95
|
+
irb(main):044:0> OrderItem.to_yaml
|
96
|
+
TypeError: can't dump anonymous class Class
|
97
|
+
irb(main):045:0> OrderItem.chainable
|
98
|
+
=> #<Module:0xb6fdd73c>
|
99
|
+
irb(main):046:0> OrderItem._valid_model
|
100
|
+
=> nil
|
101
|
+
irb(main):047:0> OrderItem.properties
|
102
|
+
=> #<PropertySet:{#<Property:OrderItem:id>,#<Property:OrderItem:inverted>,#<Property:OrderItem:count>,#<Property:OrderItem:size>,#<Property:OrderItem:color>,#<Property:OrderItem:unit_price>,#<Property:OrderItem:product_slug>,#<Property:OrderItem:order_variable_symbol>,#<Property:OrderItem:color_id>,#<Property:OrderItem:size_height>,#<Property:OrderItem:size_width>}>
|
103
|
+
irb(main):048:0> Order.tap
|
104
|
+
LocalJumpError: no block given
|
105
|
+
irb(main):049:0> Order.type
|
106
|
+
(irb):49: warning: Object#type is deprecated; use Object#class
|
107
|
+
=> Class
|
108
|
+
irb(main):050:0> o = Order
|
109
|
+
=> Order
|
110
|
+
irb(main):051:0> o.gen_attrs
|
111
|
+
NoMethodError: undefined method `new_record?' for "#ffff":String
|
112
|
+
from :0irb(main):052:0> o.validators
|
113
|
+
=> #<DataMapper::Validate::ContextualValidators:0xb6fdd020 @contexts={:default=>[#<DataMapper::Validate::RequiredFieldValidator:0xb6fdd084 @if_clause=nil, @options={:message=>"Zákazník musí být vyplněn", :context=>:default}, @unless_clause=nil, @field_name=:customer>, #<DataMapper::Validate::WithinValidator:0xb6fd0eb0 @if_clause=nil, @options={:message=>nil, :context=>:default, :set=>[:paypal, :personally, :cod, :transfer]}, @unless_clause=nil, @field_name=:payment_type>, #<DataMapper::Validate::WithinValidator:0xb6fca6dc @if_clause=nil, @options={:message=>nil, :context=>:default, :set=>[:unprocessed, :processed]}, @unless_clause=nil, @field_name=:status>, #<DataMapper::Validate::PrimitiveValidator:0xb6fc6988 @if_clause=nil, @options={:message=>nil, :context=>:default, :allow_nil=>true}, @unless_clause=nil, @field_name=:created_at>, #<DataMapper::Validate::PrimitiveValidator:0xb6fbbac4 @if_clause=nil, @options={:message=>nil, :context=>:default, :allow_nil=>true}, @unless_clause=nil, @field_name=:updated_at>, #<DataMapper::Validate::LengthValidator:0xb6fb16a0 @range=nil, @if_clause=nil, @min=nil, @equal=nil, @options={:message=>nil, :maximum=>50, :context=>:default, :allow_nil=>true}, @validation_method=:max, @unless_clause=nil, @max=50, @field_name=:referer>, #<DataMapper::Validate::PrimitiveValidator:0xb6faddac @if_clause=nil, @options={:message=>nil, :maximum=>50, :context=>:default, :allow_nil=>true}, @unless_clause=nil, @field_name=:referer>, #<DataMapper::Validate::LengthValidator:0xb6e66430 @range=nil, @if_clause=nil, @min=nil, @equal=nil, @options={:message=>nil, :maximum=>50, :context=>:default, :allow_nil=>true}, @validation_method=:max, @unless_clause=nil, @max=50, @field_name=:customer_email>, #<DataMapper::Validate::PrimitiveValidator:0xb6e6493c @if_clause=nil, @options={:message=>nil, :maximum=>50, :context=>:default, :allow_nil=>true}, @unless_clause=nil, @field_name=:customer_email>]}>
|
114
|
+
irb(main):053:0> o.options
|
115
|
+
=> nil
|
116
|
+
irb(main):054:0> o.to_yaml_style
|
117
|
+
=> nil
|
118
|
+
irb(main):055:0> o.subclass
|
119
|
+
ArgumentError: wrong number of arguments (0 for 1)
|
120
|
+
irb(main):056:0> o.present?
|
121
|
+
=> true
|
122
|
+
irb(main):057:0> o.args_for
|
123
|
+
ArgumentError: wrong number of arguments (0 for 1)
|
124
|
+
irb(main):058:0> o.in?
|
125
|
+
ArgumentError: wrong number of arguments (0 for 1)
|
126
|
+
irb(main):059:0> o.to_query
|
127
|
+
ArgumentError: wrong number of arguments (0 for 2)
|
128
|
+
irb(main):060:0> o.orig_auto_generate_validations
|
129
|
+
ArgumentError: wrong number of arguments (0 for 1)
|
130
|
+
irb(main):061:0> o.many_to_one_relationships
|
131
|
+
=> [#<DataMapper::Associations::Relationship:0xb6fd9d58 @repository_name=:default, @parent_model=Customer, @parent_properties=nil, @name=:customer, @child_key=#<PropertySet:{#<Property:Order:customer_email>}>, @child_model=Order, @parent_key=#<PropertySet:{#<Property:Customer:email>}>, @options={}, @query={}, @child_properties=nil>]
|
132
|
+
irb(main):062:0> o.unique
|
133
|
+
NoMethodError: undefined method `arity' for nil:NilClass
|
data/dm-spec.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
begin
|
2
|
+
require "rubygems/specification"
|
3
|
+
rescue SecurityError
|
4
|
+
# http://gems.github.com
|
5
|
+
end
|
6
|
+
|
7
|
+
VERSION = "0.9.10"
|
8
|
+
SPECIFICATION = ::Gem::Specification.new do |s|
|
9
|
+
s.name = "dm-spec"
|
10
|
+
# s.version = Rango::VERSION
|
11
|
+
s.version = VERSION
|
12
|
+
s.authors = ["Jakub Šťastný aka Botanicus"]
|
13
|
+
s.homepage = "http://github.com/botanicus/dm-spec"
|
14
|
+
s.summary = "Some rSpec matchers for DataMapper"
|
15
|
+
# s.description = "" # TODO: long description
|
16
|
+
s.cert_chain = nil
|
17
|
+
s.email = ["knava.bestvinensis", "gmail.com"].join("@")
|
18
|
+
s.files = Dir.glob("**/*") - Dir.glob("pkg/*")
|
19
|
+
s.add_dependency "dm-core"
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
# s.required_ruby_version = ::Gem::Requirement.new(">= 1.9.1")
|
22
|
+
# s.rubyforge_project = "rango"
|
23
|
+
end
|
data/lib/dm-spec.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# belongs to
|
2
|
+
# Product.relationships[:category]
|
3
|
+
#<DataMapper::Associations::Relationship @parent_model=Category, @name=:category, @child_key=#<PropertySet:{#<Property:Product:category_slug>}>, @child_model=Product, @parent_key=#<PropertySet:{#<Property:Category:slug>}>, @options={}>
|
4
|
+
|
5
|
+
module DataMapperMatchers
|
6
|
+
class BelongsTo
|
7
|
+
# args<Symbol>: :products
|
8
|
+
def initialize(name)
|
9
|
+
@name = name
|
10
|
+
end
|
11
|
+
|
12
|
+
# args<Model>: Category
|
13
|
+
def matches?(model)
|
14
|
+
@model = model
|
15
|
+
relationship = @model.relationships[@name]
|
16
|
+
return false unless relationship
|
17
|
+
relationship.name == @name && relationship.child_model == @model
|
18
|
+
end
|
19
|
+
|
20
|
+
def description
|
21
|
+
"belongs to"
|
22
|
+
end
|
23
|
+
|
24
|
+
def failure_message
|
25
|
+
belonging = @model.relationships.select { |name, relationship| relationship.name == @name && relationship.child_model == @model }
|
26
|
+
belonging.map! { |array| array.first }
|
27
|
+
if belonging.empty?
|
28
|
+
"expected to belongs to #@name, but does not belongs to any model"
|
29
|
+
else
|
30
|
+
"expected to belongs to #@name, but belongs to just the following relationships: #{belonging.inspect}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def negative_failure_message
|
35
|
+
"expected not to belongs to #@name, but belonged"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def belongs_to(name)
|
40
|
+
BelongsTo.new(name)
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# habtm
|
2
|
+
# Product.relationships[:colors]
|
3
|
+
#<DataMapper::Associations::RelationshipChain @parent_model=Product, @name=:color_products, @mutable=true, @child_key=#<PropertySet:{#<Property:ColorProduct:product_slug>}>, @child_model="Color", @parent_key=#<PropertySet:{#<Property:Product:slug>}>, @remote_relationship_name="colors", @options={:repository_name=>:default, :near_relationship_name=>:color_products, :parent_key=>nil, :child_key=>nil, :remote_relationship_name=>"colors", :child_model=>"Color", :min=>0, :parent_model=>Product, :max=>Infinity}, @near_relationship_name=:color_products>
|
4
|
+
|
5
|
+
module DataMapperMatchers
|
6
|
+
class HasAndBelongsToMany
|
7
|
+
# args<Symbol>: :products
|
8
|
+
def initialize(name)
|
9
|
+
@name = name
|
10
|
+
end
|
11
|
+
|
12
|
+
# args<Model>: Category
|
13
|
+
def matches?(model)
|
14
|
+
@model = model
|
15
|
+
relationship = @model.relationships[@name]
|
16
|
+
return false unless relationship
|
17
|
+
relationship.class == DataMapper::Associations::RelationshipChain && relationship.child_model == @model
|
18
|
+
end
|
19
|
+
|
20
|
+
def description
|
21
|
+
"has and belongs to many"
|
22
|
+
end
|
23
|
+
|
24
|
+
def failure_message
|
25
|
+
# TODO: filter just n:n relationships
|
26
|
+
relationships = @model.relationships.map { |name, relationship| relationship.name }.inspect
|
27
|
+
"expected to has and belongs to many #@name, but has just the following relationships: #{relationships}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def negative_failure_message
|
31
|
+
"expected not to has and belongs to many #@name, but had"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def has_and_belongs_to_many(name)
|
36
|
+
HasAndBelongsToMany.new(name)
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# has 1
|
2
|
+
# Product.relationships[:item]
|
3
|
+
#<DataMapper::Associations::Relationship @parent_model=Product, @name=:item, @child_key=#<PropertySet:{#<Property:OrderItem:product_slug>}>, @child_model=OrderItem, @parent_key=#<PropertySet:{#<Property:Product:slug>}>, @options={:min=>1, :class_name=>"OrderItem", :max=>1}>
|
4
|
+
|
5
|
+
# has n
|
6
|
+
# Category.relationships[:products]
|
7
|
+
#<DataMapper::Associations::Relationship @parent_model=Category, @name=:products, @child_key=#<PropertySet:{#<Property:Product:category_slug>}>, @child_model=Product, @parent_key=#<PropertySet:{#<Property:Category:slug>}>, @options={:min=>0, :max=>Infinity}>
|
8
|
+
|
9
|
+
module DataMapperMatchers
|
10
|
+
class HasMany
|
11
|
+
def initialize(name, options)
|
12
|
+
@name = name
|
13
|
+
@options = options
|
14
|
+
end
|
15
|
+
|
16
|
+
# args<Model>: Category
|
17
|
+
def matches?(model)
|
18
|
+
@model = model
|
19
|
+
relationship = @model.relationships[@name]
|
20
|
+
return false unless relationship
|
21
|
+
relationship.parent_model == @model && @options.all? { |key, value| relationship.options[key] == value }
|
22
|
+
end
|
23
|
+
|
24
|
+
def description
|
25
|
+
"has many"
|
26
|
+
end
|
27
|
+
|
28
|
+
def failure_message
|
29
|
+
# TODO: filter just has many relationships
|
30
|
+
properties = @model.properties.entries.map { |property| property.name }.inspect
|
31
|
+
"expected to has many #@name, but has just the following properties: #{properties}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def negative_failure_message
|
35
|
+
"expected to not has many #@name, but had"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def has_many(name, options = Hash.new)
|
40
|
+
defaults = {:min => 0, :max => 1.0 / 0}
|
41
|
+
HasMany.new(name, defaults.merge(options))
|
42
|
+
end
|
43
|
+
|
44
|
+
def has_one(name, options = Hash.new)
|
45
|
+
defaults = {:min => 1, :max => 1}
|
46
|
+
HasMany.new(name, defaults.merge(options))
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# Category.properties[:expected]
|
2
|
+
# => #<Property:Category:expected>
|
3
|
+
# Category.properties.has_property? :expected
|
4
|
+
# => true
|
5
|
+
|
6
|
+
module DataMapperMatchers
|
7
|
+
class HasProperty
|
8
|
+
def initialize(expected)
|
9
|
+
@expected = expected
|
10
|
+
end
|
11
|
+
|
12
|
+
# Category.should has_property(:id)
|
13
|
+
def matches?(model)
|
14
|
+
@model = model
|
15
|
+
return @model.properties.has_property?(@expected)
|
16
|
+
end
|
17
|
+
|
18
|
+
def description
|
19
|
+
"has property"
|
20
|
+
end
|
21
|
+
|
22
|
+
def failure_message
|
23
|
+
properties = @model.properties.entries.map { |property| property.name }
|
24
|
+
"expected to has property #@expected, but has just the following properties: #{properties}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def negative_failure_message
|
28
|
+
"expected to not has property #@expected, but had"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def has_property(expected)
|
33
|
+
HasProperty.new(expected)
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# Category.properties[:expected]
|
2
|
+
# => #<Timestamps:Category:expected>
|
3
|
+
# Category.properties.has_timestamps? :expected
|
4
|
+
# => true
|
5
|
+
|
6
|
+
module DataMapperMatchers
|
7
|
+
class HasTimestamps
|
8
|
+
def initialize(*expected)
|
9
|
+
# Post.should has_timestamps => :created_at, :updated_at
|
10
|
+
expected.push(:at) if expected.empty?
|
11
|
+
if [:at, :on].include?(expected.first)
|
12
|
+
# Post.should has_timestamps(:at)
|
13
|
+
@expected = ["created_#{expected}", "updated_#{expected}"]
|
14
|
+
else
|
15
|
+
# Post.should has_timestamps(:created_at)
|
16
|
+
@expected = expected
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Category.should has_timestamps(:id)
|
21
|
+
def matches?(model)
|
22
|
+
@model = model
|
23
|
+
loaded && included && has_timestamps
|
24
|
+
end
|
25
|
+
|
26
|
+
def loaded
|
27
|
+
$LOADED_FEATURES.any? { |file| File.basename(file).eql?("dm-timestamps.rb") }
|
28
|
+
end
|
29
|
+
|
30
|
+
def included
|
31
|
+
@model.respond_to?(:timestamps) # DataMapper::Timestamp model is included
|
32
|
+
end
|
33
|
+
|
34
|
+
def has_timestamps
|
35
|
+
@expected.all { |method| model.new.respond_to?(method) }
|
36
|
+
end
|
37
|
+
|
38
|
+
def description
|
39
|
+
"has timestamps"
|
40
|
+
end
|
41
|
+
|
42
|
+
def failure_message
|
43
|
+
properties = @model.properties.entries.map { |timestamps| timestamps.name }
|
44
|
+
"expected to has timestamps #@expected, but has just the following properties: #{properties}"
|
45
|
+
end
|
46
|
+
|
47
|
+
def negative_failure_message
|
48
|
+
"expected not to not timestamps #@expected, but had"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def has_timestamps(expected)
|
53
|
+
HasTimestamps.new(expected)
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', "spec_helper")
|
2
|
+
require "spec/matchers/dm/belongs_to"
|
3
|
+
|
4
|
+
class Post
|
5
|
+
include DataMapper::Resource
|
6
|
+
property :id, Serial
|
7
|
+
belongs_to :category
|
8
|
+
end
|
9
|
+
|
10
|
+
class Category
|
11
|
+
include DataMapper::Resource
|
12
|
+
property :id, Serial
|
13
|
+
has n, :posts
|
14
|
+
end
|
15
|
+
|
16
|
+
describe DataMapperMatchers::BelongsTo do
|
17
|
+
it "should pass for working associations" do
|
18
|
+
lambda { Post.should belongs_to(:category) }.should_not fail
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should fail for non existing working associations" do
|
22
|
+
lambda { Post.should_not belongs_to(:category) }.should fail_with("expected not to belongs to category, but belonged")
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should fail for non existing working associations" do
|
26
|
+
lambda { Post.should belongs_to(:items) }.should fail_with("expected to belongs to items, but does not belongs to any model")
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', "spec_helper")
|
2
|
+
require "spec/matchers/dm/has_and_belongs_to_many"
|
3
|
+
|
4
|
+
class Post
|
5
|
+
include DataMapper::Resource
|
6
|
+
property :id, Serial
|
7
|
+
has n, :tags, :through => Resource
|
8
|
+
end
|
9
|
+
|
10
|
+
class Tag
|
11
|
+
include DataMapper::Resource
|
12
|
+
property :id, Serial
|
13
|
+
has n, :posts, :through => Resource
|
14
|
+
end
|
15
|
+
|
16
|
+
describe DataMapperMatchers::BelongsTo do
|
17
|
+
it "should pass for working associations" do
|
18
|
+
Post.should has_and_belongs_to_many(:tags)
|
19
|
+
Tag.should has_and_belongs_to_many(:posts)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should fail for non existing working associations" do
|
23
|
+
lambda { Post.should_not has_and_belongs_to_many(:tags) }.should fail
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should fail for non existing working associations" do
|
27
|
+
lambda { Post.should has_and_belongs_to_many(:items) }.should fail_with("expected to has and belongs to many items, but has just the following relationships: [:post_tags, :post_tags, :category]")
|
28
|
+
end
|
29
|
+
end
|
File without changes
|
File without changes
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', "spec_helper")
|
2
|
+
require "spec/matchers/dm/has_timestamps"
|
3
|
+
|
4
|
+
class Post
|
5
|
+
include DataMapper::Resource
|
6
|
+
property :id, Serial
|
7
|
+
belongs_to :category
|
8
|
+
end
|
9
|
+
|
10
|
+
class Category
|
11
|
+
include DataMapper::Resource
|
12
|
+
property :id, Serial
|
13
|
+
has n, :posts
|
14
|
+
end
|
15
|
+
|
16
|
+
describe DataMapperMatchers::HasTimestamps do
|
17
|
+
it "should pass for working associations" do
|
18
|
+
Post.should belongs_to(:category)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should fail for non existing working associations" do
|
22
|
+
lambda { Post.should_not belongs_to(:category) }.should fail_with("expected not to belongs to category, but belonged")
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should fail for non existing working associations" do
|
26
|
+
lambda { Post.should belongs_to(:items) }.should fail_with("expected to belongs to items, but has just the following relationships: [:post_tags, :post_tags, :category]")
|
27
|
+
end
|
28
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
$: << File.dirname(__FILE__) + "/../lib"
|
2
|
+
require "dm-core"
|
3
|
+
|
4
|
+
DataMapper.setup(:default, "sqlite3::memory")
|
5
|
+
|
6
|
+
# must be initialized for include
|
7
|
+
module DataMapperMatchers
|
8
|
+
end
|
9
|
+
|
10
|
+
Spec::Runner.configure do |config|
|
11
|
+
config.include(DataMapperMatchers)
|
12
|
+
config.before(:each) do
|
13
|
+
DataMapper.auto_migrate!
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
##############
|
18
|
+
# from rspec #
|
19
|
+
##############
|
20
|
+
module Spec
|
21
|
+
module Example
|
22
|
+
class NonStandardError < Exception; end
|
23
|
+
end
|
24
|
+
|
25
|
+
module Matchers
|
26
|
+
def fail
|
27
|
+
raise_error(Spec::Expectations::ExpectationNotMetError)
|
28
|
+
end
|
29
|
+
|
30
|
+
def fail_with(message)
|
31
|
+
raise_error(Spec::Expectations::ExpectationNotMetError, message)
|
32
|
+
end
|
33
|
+
|
34
|
+
def exception_from(&block)
|
35
|
+
exception = nil
|
36
|
+
begin
|
37
|
+
yield
|
38
|
+
rescue StandardError => e
|
39
|
+
exception = e
|
40
|
+
end
|
41
|
+
exception
|
42
|
+
end
|
43
|
+
|
44
|
+
def run_with(options)
|
45
|
+
::Spec::Runner::CommandLine.run(options)
|
46
|
+
end
|
47
|
+
|
48
|
+
def with_ruby(version)
|
49
|
+
yield if RUBY_VERSION =~ Regexp.compile("^#{version.to_s}")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def with_sandboxed_options
|
55
|
+
attr_reader :options
|
56
|
+
|
57
|
+
before(:each) do
|
58
|
+
@original_rspec_options = ::Spec::Runner.options
|
59
|
+
::Spec::Runner.use(@options = ::Spec::Runner::Options.new(StringIO.new, StringIO.new))
|
60
|
+
end
|
61
|
+
|
62
|
+
after(:each) do
|
63
|
+
::Spec::Runner.use(@original_rspec_options)
|
64
|
+
end
|
65
|
+
|
66
|
+
yield
|
67
|
+
end
|
68
|
+
|
69
|
+
def with_sandboxed_config
|
70
|
+
attr_reader :config
|
71
|
+
|
72
|
+
before(:each) do
|
73
|
+
@config = ::Spec::Runner::Configuration.new
|
74
|
+
@original_configuration = ::Spec::Runner.configuration
|
75
|
+
spec_configuration = @config
|
76
|
+
::Spec::Runner.instance_eval {@configuration = spec_configuration}
|
77
|
+
end
|
78
|
+
|
79
|
+
after(:each) do
|
80
|
+
original_configuration = @original_configuration
|
81
|
+
::Spec::Runner.instance_eval {@configuration = original_configuration}
|
82
|
+
::Spec::Example::ExampleGroupFactory.reset
|
83
|
+
end
|
84
|
+
|
85
|
+
yield
|
86
|
+
end
|
87
|
+
|
88
|
+
module Spec
|
89
|
+
module Example
|
90
|
+
module Resettable
|
91
|
+
def reset # :nodoc:
|
92
|
+
@before_all_parts = nil
|
93
|
+
@after_all_parts = nil
|
94
|
+
@before_each_parts = nil
|
95
|
+
@after_each_parts = nil
|
96
|
+
end
|
97
|
+
end
|
98
|
+
class ExampleGroup
|
99
|
+
extend Resettable
|
100
|
+
end
|
101
|
+
class ExampleGroupDouble < ExampleGroup
|
102
|
+
::Spec::Runner.options.remove_example_group self
|
103
|
+
def register_example_group(klass)
|
104
|
+
#ignore
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dm-spec
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.9.10
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- "Jakub \xC5\xA0\xC5\xA5astn\xC3\xBD aka Botanicus"
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain:
|
11
|
+
date: 2009-11-26 00:00:00 +00:00
|
12
|
+
default_executable:
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: dm-core
|
16
|
+
type: :runtime
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: "0"
|
23
|
+
version:
|
24
|
+
description:
|
25
|
+
email: knava.bestvinensis@gmail.com
|
26
|
+
executables: []
|
27
|
+
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files: []
|
31
|
+
|
32
|
+
files:
|
33
|
+
- dm-spec.gemspec
|
34
|
+
- lib/dm-spec.rb
|
35
|
+
- lib/spec/matchers/dm/belongs_to.rb
|
36
|
+
- lib/spec/matchers/dm/has_and_belongs_to_many.rb
|
37
|
+
- lib/spec/matchers/dm/has_many.rb
|
38
|
+
- lib/spec/matchers/dm/has_property.rb
|
39
|
+
- lib/spec/matchers/dm/has_timestamps.rb
|
40
|
+
- LICENSE
|
41
|
+
- Rakefile
|
42
|
+
- README.textile
|
43
|
+
- spec/dm/belongs_to_spec.rb
|
44
|
+
- spec/dm/has_and_belongs_to_many_spec.rb
|
45
|
+
- spec/dm/has_many_spec.rb
|
46
|
+
- spec/dm/has_property_spec.rb
|
47
|
+
- spec/dm/has_timestamps_spec.rb
|
48
|
+
- spec/spec.opts
|
49
|
+
- spec/spec_helper.rb
|
50
|
+
- TODO
|
51
|
+
has_rdoc: true
|
52
|
+
homepage: http://github.com/botanicus/dm-spec
|
53
|
+
licenses: []
|
54
|
+
|
55
|
+
post_install_message:
|
56
|
+
rdoc_options: []
|
57
|
+
|
58
|
+
require_paths:
|
59
|
+
- lib
|
60
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: "0"
|
65
|
+
version:
|
66
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: "0"
|
71
|
+
version:
|
72
|
+
requirements: []
|
73
|
+
|
74
|
+
rubyforge_project:
|
75
|
+
rubygems_version: 1.3.5
|
76
|
+
signing_key:
|
77
|
+
specification_version: 3
|
78
|
+
summary: Some rSpec matchers for DataMapper
|
79
|
+
test_files: []
|
80
|
+
|