ricordami 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -1,16 +1,22 @@
1
1
  # Changelog #
2
2
 
3
- ## 0.0.3 (March 12th, 2011)
3
+ ## 0.0.4 (March 13th, 2011) ##
4
+
5
+ - add a scope option to validates_uniqueness_of validation macro
6
+ - allow to pass nil when creating a new instance
7
+ - added a spec for update_attributes with an invalid model
8
+
9
+ ## 0.0.3 (March 12th, 2011) ##
4
10
 
5
11
  - added serialization (use: "model\_can :be_serialized") to have
6
12
  access to Model#to_json and Model#to_xml
7
13
 
8
- ## 0.0.2 (March 5th, 2011)
14
+ ## 0.0.2 (March 5th, 2011) ##
9
15
 
10
16
  - added examples and fixed README
11
17
  - created a basic Ricordami::Model#to_s method
12
18
 
13
- ## 0.0.1 (March 5th, 2011)
19
+ ## 0.0.1 (March 5th, 2011) ##
14
20
 
15
21
  Initial release.
16
22
 
@@ -36,6 +36,7 @@ module Ricordami
36
36
  attr_reader :attributes
37
37
 
38
38
  def initialize(attrs = {})
39
+ attrs = {} if attrs.nil?
39
40
  @attributes = {}.with_indifferent_access
40
41
  @reloading = false
41
42
  update_mem_attributes(attrs) unless attrs.empty?
@@ -12,8 +12,7 @@ module Ricordami
12
12
  end
13
13
 
14
14
  def index(options = {})
15
- # for now we can only create unique indices
16
- options.assert_valid_keys(:unique, :get_by, :value)
15
+ options.assert_valid_keys(:unique, :get_by, :value, :scope)
17
16
  fields = options.delete(:unique)
18
17
  return unique_index(fields, options) if fields.present?
19
18
  field = options.delete(:value)
@@ -4,13 +4,17 @@ module Ricordami
4
4
  class UniqueIndex
5
5
  SEPARATOR = "_-::-_"
6
6
 
7
- attr_reader :model, :fields, :name, :need_get_by
7
+ attr_reader :model, :fields, :name, :need_get_by, :scope
8
8
 
9
9
  def initialize(model, fields, options = {})
10
10
  @model = model
11
- @fields = [fields].flatten.map(&:to_sym)
12
- @need_get_by = options[:get_by] && @fields != [:id]
11
+ @fields = normalize_array(fields)
13
12
  @name = @fields.join("_").to_sym
13
+ @need_get_by = options[:get_by] && @fields != [:id]
14
+ if options.has_key?(:scope)
15
+ @scope = normalize_array(options[:scope])
16
+ @fields.push(*@scope)
17
+ end
14
18
  end
15
19
 
16
20
  def uidx_key_name
@@ -22,7 +26,7 @@ module Ricordami
22
26
  end
23
27
 
24
28
  def add(id, value)
25
- value = value.join(SEPARATOR) if value.is_a?(Array)
29
+ value = normalize_value(value)
26
30
  @model.redis.sadd(uidx_key_name, value)
27
31
  @model.redis.hset(ref_key_name, value, id) if @need_get_by
28
32
  end
@@ -35,7 +39,7 @@ module Ricordami
35
39
  return commands
36
40
  end
37
41
  @model.redis.hdel(ref_key_name, id) if @need_get_by
38
- value = value.join(SEPARATOR) if value.is_a?(Array)
42
+ value = normalize_value(value)
39
43
  @model.redis.srem(uidx_key_name, value)
40
44
  end
41
45
 
@@ -55,5 +59,16 @@ module Ricordami
55
59
  def include?(value)
56
60
  @model.redis.sismember(uidx_key_name, value)
57
61
  end
62
+
63
+ def normalize_value(value)
64
+ value.is_a?(Array) ? value.join(SEPARATOR) : value
65
+ end
66
+
67
+ private
68
+
69
+ def normalize_array(array)
70
+ return [] if array.nil?
71
+ [array].flatten.map(&:to_sym)
72
+ end
58
73
  end
59
74
  end
@@ -6,6 +6,10 @@ module Ricordami
6
6
  return true unless record.new_record? || record.send(:attribute_changed?, attribute)
7
7
  index_name = attribute.to_sym
8
8
  index = record.class.indices[index_name]
9
+ if index.scope
10
+ scope_values = index.scope.map { |field| record.send(field) }
11
+ value = index.normalize_value([value].push(*scope_values))
12
+ end
9
13
  if index.include?(value)
10
14
  attr_def = record.class.attributes[attribute]
11
15
  unless record.persisted? && attr_def.read_only?
@@ -15,7 +19,7 @@ module Ricordami
15
19
  end
16
20
 
17
21
  def setup(klass)
18
- attributes.each { |attribute| klass.index :unique => attribute }
22
+ attributes.each { |attribute| klass.index :unique => attribute, :scope => options[:scope] }
19
23
  end
20
24
  end
21
25
  end
@@ -1,3 +1,3 @@
1
1
  module Ricordami
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -50,7 +50,7 @@ describe Ricordami::CanBeValidated do
50
50
  end
51
51
  end
52
52
 
53
- describe "#save" do
53
+ describe "#save and #update_attributes" do
54
54
  uses_constants("Post")
55
55
 
56
56
  before(:each) do
@@ -69,6 +69,11 @@ describe Ricordami::CanBeValidated do
69
69
  it "can save if it is not valid but passed :validate => false" do
70
70
  Post.new.save(:validate => false).should be_true
71
71
  end
72
+
73
+ it "can't #update_attributes if it is not valid" do
74
+ post = Post.create(:title => "blah")
75
+ post.update_attributes(:title => "").should be_false
76
+ end
72
77
  end
73
78
 
74
79
  describe "validate attribute uniqueness" do
@@ -111,5 +116,13 @@ describe Ricordami::CanBeValidated do
111
116
  fred.should have(1).error
112
117
  fred.errors[:wife].should == ["is already used"]
113
118
  end
119
+
120
+ it "allows to validate the uniqueness using a scope" do
121
+ User.validates_uniqueness_of(:wife, :scope => :username)
122
+ serge = User.create(:id => "serge", :username => "Gainsbourg", :wife => "Rita")
123
+ fred = User.new(:username => "Chichin", :wife => "Rita")
124
+ fred.should be_valid
125
+ fred.should have(0).errors
126
+ end
114
127
  end
115
128
  end
@@ -38,6 +38,12 @@ describe Ricordami::HasAttributes do
38
38
  attribute.initial_value.should == "2"
39
39
  attribute.initial_value.should == "3"
40
40
  end
41
+
42
+ it "can create a new instance without parameters, with nil or an empty hash" do
43
+ Boat.new.attributes.should == {"id" => nil}
44
+ Boat.new(nil).attributes.should == {"id" => nil}
45
+ Boat.new({}).attributes.should == {"id" => nil}
46
+ end
41
47
  end
42
48
 
43
49
  describe "an instance" do
@@ -27,6 +27,13 @@ describe Ricordami::HasIndices do
27
27
  Car.indices[:model].should == index
28
28
  end
29
29
 
30
+ it "can give a scope to a unique index with :scope option" do
31
+ Car.attribute :brand
32
+ index = Car.index :unique => :model, :scope => :brand
33
+ Car.indices[:model].scope.should == [:brand]
34
+ Car.indices[:model].fields.should == [:model, :brand]
35
+ end
36
+
30
37
  it "discards the subsequent declarations if the same index is created more than once" do
31
38
  Car.index :unique => :model, :get_by => true
32
39
  Car.indices[:model].need_get_by.should be_true
@@ -28,9 +28,6 @@ describe Ricordami::Model do
28
28
  user.to_model.should == user
29
29
  end
30
30
 
31
- it "has a simple to_s method" do
32
- end
33
-
34
31
  describe "#to_key" do
35
32
  before(:each) do
36
33
  @user = User.new
@@ -6,6 +6,7 @@ describe Ricordami::UniqueIndex do
6
6
  before(:each) do
7
7
  create_constant("DataSource")
8
8
  DataSource.attribute :name
9
+ DataSource.attribute :owner
9
10
  @index = subject.new(DataSource, :id)
10
11
  end
11
12
 
@@ -15,6 +16,12 @@ describe Ricordami::UniqueIndex do
15
16
  @index.name.should == :id
16
17
  end
17
18
 
19
+ it "can have a scope" do
20
+ index = subject.new(DataSource, :id, :scope => :owner)
21
+ index.scope.should == [:owner]
22
+ index.fields.should == [:id, :owner]
23
+ end
24
+
18
25
  it "returns its internal index name with #uidx_key_name" do
19
26
  @index.uidx_key_name.should == "DataSource:udx:id"
20
27
  end
@@ -38,4 +38,18 @@ describe Ricordami::UniqueValidator do
38
38
  validator.validate_each(sophie, :name, record.name)
39
39
  sophie.errors[:name].should == ["come on, man!"]
40
40
  end
41
+
42
+ it "accepts a scope option to limit the unicity constraint" do
43
+ Call.attribute :family
44
+ validator = Ricordami::UniqueValidator.new(:attributes => [:name], :scope => :family)
45
+ validator.setup(Call)
46
+ Call.create(:name => "john", :family => "jones")
47
+ john = Call.new(:name => "john", :family => "jones")
48
+ validator.validate_each(john, :name, john.name)
49
+ john.should have(1).error
50
+ john.family = "doe"
51
+ john.errors.clear
52
+ validator.validate_each(john, :name, john.name)
53
+ john.should have(0).errors
54
+ end
41
55
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: ricordami
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.3
5
+ version: 0.0.4
6
6
  platform: ruby
7
7
  authors:
8
8
  - Mathieu Lajugie
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-03-12 00:00:00 -08:00
13
+ date: 2011-03-12 23:00:00 -08:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency