rrod 1.0.0.alpha.1 → 1.0.0.alpha.2

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.
@@ -0,0 +1,15 @@
1
+ module Rrod
2
+ module Model
3
+ module Validations
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ include ActiveModel::Validations
8
+ end
9
+
10
+ def save(options={})
11
+ options.fetch(:validate, true) ? (valid? and super()) : super()
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,29 @@
1
+ module Rrod
2
+ module Model
3
+ module Validations
4
+
5
+ class AssociatedValidator < ActiveModel::EachValidator
6
+ def validate_each(record, attribute, value)
7
+ return if Array(value).collect{ |r| r.nil? || r.valid? }.all?
8
+ record.errors.add(attribute, error_message_for(attribute, value))
9
+ end
10
+
11
+ private
12
+
13
+ def error_message_for(attribute, associated_records)
14
+ Array(associated_records).map(&:errors).reject(&:blank?).map(&:full_messages).map(&:to_sentence).flatten.join('; ')
15
+ end
16
+
17
+ end
18
+
19
+ module ClassMethods
20
+
21
+ def validates_associated(*attrs)
22
+ validates_with AssociatedValidator, _merge_attributes(attrs)
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+ end
29
+ end
data/lib/rrod/query.rb CHANGED
@@ -27,4 +27,4 @@ module Rrod
27
27
  end
28
28
 
29
29
  end
30
- end
30
+ end
@@ -18,7 +18,7 @@ module Rrod
18
18
  fail "Test server not working: #{Rrod::TestServer.fatal}"
19
19
  end
20
20
 
21
- if example.metadata[:test_server] == false
21
+ if ::RSpec.current_example.metadata[:test_server] == false
22
22
  Rrod::TestServer.stop
23
23
  else
24
24
  Rrod::TestServer.create unless Rrod::TestServer.exist?
@@ -32,9 +32,10 @@ module Rrod
32
32
 
33
33
  config.after(:each, :integration => true) do
34
34
  # i really don't understand this...
35
+ # well the 'example' needs to be accessed another way, Rspec.current_example.
35
36
  if !Rrod::TestServer.fatal &&
36
37
  Rrod::TestServer.started? &&
37
- example.metadata[:test_server] != false
38
+ ::RSpec.current_example.metadata[:test_server] != false
38
39
  Rrod::TestServer.drop
39
40
  end
40
41
  end
data/lib/rrod/version.rb CHANGED
@@ -1,2 +1,2 @@
1
1
  Rrod = Module.new unless defined? Rrod
2
- Rrod::VERSION = '1.0.0.alpha.1'
2
+ Rrod::VERSION = '1.0.0.alpha.2'
@@ -10,7 +10,7 @@ describe Rrod::Model do
10
10
  describe "instantiation" do
11
11
  it "can create an object with an arbitrary hash" do
12
12
  expect(instance.wheels).to eq 4
13
- expect(instance.color).to eq :black
13
+ # @TODO expect(instance.color).to eq :black
14
14
  expect(instance.make).to eq 'Jeep'
15
15
  end
16
16
 
@@ -20,7 +20,7 @@ describe Rrod::Model do
20
20
  end
21
21
 
22
22
  it "manages attribute keys as strings" do
23
- expect(instance.attributes).to eq hash.stringify_keys
23
+ expect(instance.attributes.keys).to eq hash.stringify_keys.keys
24
24
  end
25
25
 
26
26
  it "ignores modifications to the attribute hash" do
@@ -57,8 +57,19 @@ describe Rrod::Model do
57
57
  end
58
58
  end
59
59
 
60
- describe "query generation" do
61
- it "lets you use strings with apostrophes in them"
60
+ end
61
+
62
+ describe "defaults" do
63
+ let(:model) { Class.new(Car) { attribute :wheels, Integer, default: 4 } }
64
+ let(:instance) { model.new }
65
+
66
+ it "will return the default when reading a nil value" do
67
+ expect(instance.wheels).to eq 4
68
+ end
69
+
70
+ it "will set the default to the read value" do
71
+ instance.wheels
72
+ expect(instance.instance_variable_get(:@attributes)['wheels']).to eq 4
62
73
  end
63
74
  end
64
75
  end
@@ -30,10 +30,13 @@ describe Rrod::Model::Attribute do
30
30
  end
31
31
 
32
32
  describe "defaults" do
33
+ let(:default) { attribute.default(instance) }
34
+
33
35
  context "when a value" do
34
36
  let(:options) { {default: 'SOO fluffy!'} }
37
+
35
38
  it "can provide a default value" do
36
- expect(attribute.default).to eq 'SOO fluffy!'
39
+ expect(default).to eq 'SOO fluffy!'
37
40
  end
38
41
  end
39
42
 
@@ -41,7 +44,17 @@ describe Rrod::Model::Attribute do
41
44
  let(:options) { {default: -> { 'alligator' }} }
42
45
 
43
46
  it "can provide a default value if a proc" do
44
- expect(attribute.default).to eq 'alligator'
47
+ expect(default).to eq 'alligator'
48
+ end
49
+
50
+ context "given an instance" do
51
+ let(:model) { Class.new { include Rrod::Model; attr_accessor :foo } }
52
+ let(:options) { {default: -> { foo.upcase }} }
53
+
54
+ it "evaluates in the context of the given instance" do
55
+ instance.foo = 'whoah'
56
+ expect(default).to eq('WHOAH')
57
+ end
45
58
  end
46
59
  end
47
60
  end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+ require 'support/models/person'
3
+
4
+ describe Rrod::Model::Callbacks do
5
+ let(:instance) { Person.new }
6
+
7
+ describe "assignment" do
8
+ it "provides callbacks" do
9
+ expect(instance).to receive(:poke)
10
+ instance.attributes = {name: 'Pooka'}
11
+ end
12
+ end
13
+
14
+ describe "validation" do
15
+ it "provides callbacks" do
16
+ expect(instance).to receive(:stuffs)
17
+ instance.valid?
18
+ end
19
+ end
20
+
21
+ describe "saving" do
22
+ it "provides callbacks" do
23
+ expect(instance).to receive(:other_stuffs)
24
+ instance.save
25
+ end
26
+
27
+ describe "create" do
28
+ it "runs when new" do
29
+ expect(instance).to receive(:created!)
30
+ expect(instance).not_to receive(:updated!)
31
+ instance.save
32
+ end
33
+
34
+ it "does not run when persisted" do
35
+ instance.instance_variable_set :@persisted, true
36
+ expect(instance).not_to receive(:created!)
37
+ instance.save
38
+ end
39
+ end
40
+
41
+ describe "update" do
42
+ before :each do
43
+ instance.instance_variable_set :@persisted, true
44
+ end
45
+
46
+ it "runs when persisted" do
47
+ expect(instance).to receive(:updated!)
48
+ expect(instance).not_to receive(:created!)
49
+ instance.save
50
+ end
51
+
52
+ it "does not run when new" do
53
+ instance.instance_variable_set :@persisted, false
54
+ expect(instance).not_to receive(:updated!)
55
+ instance.save
56
+ end
57
+ end
58
+ end
59
+
60
+ end
@@ -3,7 +3,7 @@ require 'support/models/person'
3
3
 
4
4
  describe Rrod::Model::Collection do
5
5
  let(:array) { [Pet.new] }
6
- let(:collection) { described_class.new(array) }
6
+ let(:collection) { described_class.new(Pet, array) }
7
7
 
8
8
  describe "initialization" do
9
9
  it "takes a collection" do
@@ -11,9 +11,18 @@ describe Rrod::Model::Collection do
11
11
  end
12
12
 
13
13
  it "defaults to an empty collection" do
14
- expect(described_class.new.collection).to be_an Array
14
+ expect(described_class.new(Pet).collection).to be_an Array
15
15
  end
16
16
 
17
+ describe "#build" do
18
+ it "adds to the collection" do
19
+ collection.build(name: 'Lion')
20
+ expect(collection.collection.length).to eq 2
21
+ expect(collection.collection.last.name).to eq('Lion')
22
+ end
23
+ end
24
+
25
+
17
26
  describe "errors" do
18
27
  describe "non enumerable" do
19
28
  let(:array) { Object.new }
@@ -22,14 +31,14 @@ describe Rrod::Model::Collection do
22
31
  end
23
32
  end
24
33
 
25
- describe "not all Rrod::Model" do
26
- let(:array) { [Pet.new, Object.new] }
34
+ describe "not all same Rrod::Model" do
35
+ let(:array) { [Pet.new, Address.new] }
27
36
  it "raises if not all `Rrod::Model`s" do
28
37
  expect { collection }.to raise_error(Rrod::Model::Collection::InvalidMemberTypeError)
29
38
  end
30
39
 
31
40
  it "clears the collection" do
32
- collection = described_class.new
41
+ collection = described_class.new(Pet)
33
42
  begin; collection.collection = array; rescue; end
34
43
  expect(collection.collection).to be_empty
35
44
  end
@@ -31,29 +31,29 @@ describe Rrod::Model::Finders, integration: true do
31
31
  end
32
32
 
33
33
  describe "finding by attributes in the hash" do
34
- describe "find_first_by" do
34
+ describe "find_by" do
35
35
  it "can find one" do
36
- found = model.find_first_by(make: 'Jeep')
36
+ found = model.find_by(make: 'Jeep')
37
37
  expect(found).to be_a model
38
38
  expect(found.make).to eq "Jeep"
39
39
  end
40
40
 
41
41
  it "will work properly when finding by id" do
42
- found = model.find_first_by(id: instance.id)
42
+ found = model.find_by(id: instance.id)
43
43
  expect(found).to be_a model
44
44
  end
45
45
 
46
46
  it "will return nil if one can't be found" do
47
- found = model.find_first_by(id: "id that is not there")
47
+ found = model.find_by(id: "id that is not there")
48
48
  expect(found).to be nil
49
49
  end
50
50
 
51
51
  it "will raise an exception if one can't be found with a !" do
52
- expect { model.find_first_by! zombies: true }.to raise_error(Rrod::Model::NotFound)
52
+ expect { model.find_by! zombies: true }.to raise_error(ArgumentError)
53
53
  end
54
54
  end
55
55
 
56
- describe "find_all_by" do
56
+ describe "search" do
57
57
  it "can find all" do
58
58
  founds = model.find_all_by(make: 'Jeep', wheels: 4)
59
59
  found = founds.first
@@ -62,17 +62,18 @@ describe Rrod::Model::Finders, integration: true do
62
62
  expect(found.make).to eq "Jeep"
63
63
  end
64
64
 
65
- it "will raise an exception if finding all by id" do
65
+ it "will raise an exception if searching by id" do
66
66
  expect {model.find_all_by(id: instance.id)}.to raise_error(ArgumentError)
67
67
  end
68
68
 
69
- it "will return [] if none can be found" do
70
- expect(model.find_all_by zombies: 'yes plz').to eq []
69
+ it "will return an exeception if none can be found" do
70
+ expect { model.find_all_by zombies: 'yes plz'}.to raise_error(ArgumentError)
71
71
  end
72
72
 
73
73
  it "will raise an exception if none can be found with a !" do
74
- expect { model.find_all_by! brains: :none }.to raise_error(Rrod::Model::NotFound)
74
+ expect { model.find_all_by! brains: :none }.to raise_error(ArgumentError)
75
75
  end
76
76
  end
77
77
  end
78
+
78
79
  end
@@ -20,7 +20,7 @@ describe Rrod::Model::Schema do
20
20
  end
21
21
 
22
22
  it "is using a schema if an attribute is declared" do
23
- expect(Person.schema?).to be_true
23
+ expect(Person.schema?).to be_truthy
24
24
  end
25
25
 
26
26
  describe "associations", integration: true do
@@ -54,6 +54,24 @@ describe Rrod::Model::Schema do
54
54
  expect(hash['address']).to eq 'street' => '123 Fancy Pants Lane'
55
55
  end
56
56
 
57
+ it "will set the parent on a nested model when assigned" do
58
+ instance.address = Address.new
59
+ expect(instance.address._parent).to eq(instance)
60
+ end
61
+
62
+ it "will alias the parent with method given to nested_in" do
63
+ instance.pets = [Pet.new]
64
+ expect(instance.pets.first.owner).to eq(instance)
65
+ end
66
+
67
+ end
68
+
69
+ it "raises an UncastableObjectError if object is not castable" do
70
+ expect { Pet.rrod_cast(Object.new) }.to raise_error(Rrod::Model::UncastableObjectError)
71
+ end
72
+
73
+ it "will not add ids to models instantiated via `rrod_cast`" do
74
+ expect(Pet.rrod_cast(name: 'Molle').attributes).to_not have_key('id')
57
75
  end
58
76
 
59
77
  end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rrod::Model::Timestamps do
4
+ let(:klass) { Class.new {include Rrod::Model; timestamps!} }
5
+ let(:instance) { klass.new }
6
+ let(:attribute) { Rrod::Model::Attribute }
7
+ let(:now) { Time.now }
8
+
9
+ it "provides a created_at attribute" do
10
+ expect(klass.attributes[:created_at]).to be_an attribute
11
+ end
12
+
13
+ it "provides a updated_at attribute" do
14
+ expect(klass.attributes[:updated_at]).to be_an attribute
15
+ end
16
+
17
+ describe "Time.now" do
18
+ before(:each) { Time.stub(:now).and_return(now) }
19
+
20
+ it "sets created_at upon instantiation" do
21
+ expect(instance.created_at).to eq now
22
+ end
23
+
24
+ it "sets updated_at when the object is updated" do
25
+ instance.stub(:persist).and_return(true)
26
+ expect(instance).to receive(:updated_at=).with(now)
27
+ instance.save
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+ require 'support/models/player'
3
+ require 'support/models/team'
4
+
5
+ describe Rrod::Model::Validations::AssociatedValidator do
6
+ context 'for a many association' do
7
+ # this is the same as a one association..
8
+ let(:team) { Team.new }
9
+ let(:ichiro) { Player.new(name: 'Ichiro', position: 'RF') }
10
+ let(:arod) { Player.new(position: '3B') }
11
+ let(:joeschmo) { Player.new }
12
+
13
+ before(:each) do
14
+ team.players = [ichiro, arod, joeschmo]
15
+ end
16
+
17
+ it 'is invalid when the associated records are invalid' do
18
+ expect(arod.valid?).to be false
19
+ expect(joeschmo.valid?).to be false
20
+ expect(team.valid?).to be false
21
+ end
22
+
23
+ it 'includes the associated records validation error messages in the error message' do
24
+ team.valid?
25
+ expect(team.errors[:players].size).to be 1
26
+ # maybe change this to better error messages
27
+ error_message = team.errors[:players].first
28
+ expect(error_message).to eq "Name can't be blank; Name can't be blank and Position can't be blank"
29
+ end
30
+
31
+
32
+ it 'is valid when the associated records are valid' do
33
+ expect(ichiro.valid?).to be true
34
+
35
+ arod.name = 'Alex Rodriguez'
36
+ expect(arod.valid?).to be true
37
+
38
+ joeschmo.name = 'Joe Schmo'
39
+ joeschmo.position = 'C'
40
+ expect(joeschmo.valid?).to be true
41
+
42
+ expect(team.valid?).to be true
43
+ end
44
+
45
+ end
46
+ end
@@ -1,50 +1,48 @@
1
1
  require 'spec_helper'
2
2
  require 'support/models/person'
3
3
 
4
- describe Rrod::Model do
5
- describe "validations" do
6
- let(:klass) { Person }
7
- let(:validators) { klass.validators }
8
- let(:instance) { klass.new }
9
-
10
- it "adds validations as class methods" do
11
- expect(validators.any? { |v| ActiveModel::Validations::LengthValidator === v }).to be_true
12
- end
13
-
14
- it "allows describing validations in the attribute" do
15
- expect(validators.any? { |v| ActiveModel::Validations::PresenceValidator === v }).to be_true
16
- end
17
-
18
- it "raises a no method error if no validation exists" do
19
- expect {
20
- Class.new {
21
- include Rrod::Model
22
- attribute :kittens, Integer, bunnies: true
23
- }
24
- }.to raise_error(ArgumentError, /BunniesValidator/)
25
- end
26
-
27
-
28
- it "can determine an instances validity" do
29
- expect(instance).not_to be_valid
30
- end
31
-
32
- it "will not save if invalid" do
33
- expect(instance).not_to receive(:persist)
34
- instance.save
35
- end
36
-
37
- it "will return false from saving if invalid" do
38
- expect(instance.save).to be_false
39
- end
40
-
41
- it "sets up errors properlies" do
42
- instance.valid?
43
- expect(instance.errors).to be_present
44
- end
45
-
46
- it "will allow saving when not validating" do
47
- expect(instance.save(validate: false)).to be_true
48
- end
4
+ describe Rrod::Model::Validations do
5
+ let(:klass) { Person }
6
+ let(:validators) { klass.validators }
7
+ let(:instance) { klass.new }
8
+
9
+ it "adds validations as class methods" do
10
+ expect(validators.any? { |v| ActiveModel::Validations::LengthValidator === v }).to be_truthy
11
+ end
12
+
13
+ it "allows describing validations in the attribute" do
14
+ expect(validators.any? { |v| ActiveModel::Validations::PresenceValidator === v }).to be_truthy
15
+ end
16
+
17
+ it "raises a no method error if no validation exists" do
18
+ expect {
19
+ Class.new {
20
+ include Rrod::Model
21
+ attribute :kittens, Integer, bunnies: true
22
+ }
23
+ }.to raise_error(ArgumentError, /BunniesValidator/)
24
+ end
25
+
26
+
27
+ it "can determine an instances validity" do
28
+ expect(instance).not_to be_valid
29
+ end
30
+
31
+ it "will not save if invalid" do
32
+ expect(instance).not_to receive(:persist)
33
+ instance.save
34
+ end
35
+
36
+ it "will return false from saving if invalid" do
37
+ expect(instance.save).to be_falsey
38
+ end
39
+
40
+ it "sets up errors properlies" do
41
+ instance.valid?
42
+ expect(instance.errors).to be_present
43
+ end
44
+
45
+ it "will allow saving when not validating" do
46
+ expect(instance.save(validate: false)).to be_truthy
49
47
  end
50
48
  end