morpheus 0.3.4

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.
Files changed (108) hide show
  1. data/.rvmrc +1 -0
  2. data/Gemfile +21 -0
  3. data/Gemfile.lock +134 -0
  4. data/LICENSE.txt +20 -0
  5. data/README.rdoc +44 -0
  6. data/Rakefile +48 -0
  7. data/VERSION +1 -0
  8. data/autotest/discover.rb +7 -0
  9. data/lib/ext/typhoeus.rb +37 -0
  10. data/lib/morpheus/associations/association.rb +110 -0
  11. data/lib/morpheus/associations/belongs_to_association.rb +45 -0
  12. data/lib/morpheus/associations/has_many_association.rb +70 -0
  13. data/lib/morpheus/associations/has_one_association.rb +46 -0
  14. data/lib/morpheus/base.rb +66 -0
  15. data/lib/morpheus/client/associations.rb +47 -0
  16. data/lib/morpheus/client/inflections.rb +3 -0
  17. data/lib/morpheus/client/log_subscriber.rb +64 -0
  18. data/lib/morpheus/client/railtie.rb +25 -0
  19. data/lib/morpheus/configuration.rb +49 -0
  20. data/lib/morpheus/errors.rb +32 -0
  21. data/lib/morpheus/filter.rb +18 -0
  22. data/lib/morpheus/mixins/associations.rb +55 -0
  23. data/lib/morpheus/mixins/attributes.rb +133 -0
  24. data/lib/morpheus/mixins/conversion.rb +21 -0
  25. data/lib/morpheus/mixins/filtering.rb +18 -0
  26. data/lib/morpheus/mixins/finders.rb +58 -0
  27. data/lib/morpheus/mixins/introspection.rb +25 -0
  28. data/lib/morpheus/mixins/persistence.rb +46 -0
  29. data/lib/morpheus/mixins/reflections.rb +24 -0
  30. data/lib/morpheus/mixins/request_handling.rb +34 -0
  31. data/lib/morpheus/mixins/response_parsing.rb +27 -0
  32. data/lib/morpheus/mixins/url_support.rb +36 -0
  33. data/lib/morpheus/mock.rb +66 -0
  34. data/lib/morpheus/reflection.rb +22 -0
  35. data/lib/morpheus/relation.rb +57 -0
  36. data/lib/morpheus/request.rb +41 -0
  37. data/lib/morpheus/request_cache.rb +18 -0
  38. data/lib/morpheus/request_queue.rb +44 -0
  39. data/lib/morpheus/response.rb +24 -0
  40. data/lib/morpheus/response_parser.rb +80 -0
  41. data/lib/morpheus/type_caster.rb +80 -0
  42. data/lib/morpheus/url_builder.rb +52 -0
  43. data/lib/morpheus.rb +64 -0
  44. data/morpheus.gemspec +191 -0
  45. data/spec/dummy/Rakefile +7 -0
  46. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  47. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  48. data/spec/dummy/app/models/purchase.rb +3 -0
  49. data/spec/dummy/app/resources/attendee.rb +2 -0
  50. data/spec/dummy/app/resources/author.rb +5 -0
  51. data/spec/dummy/app/resources/automobile.rb +6 -0
  52. data/spec/dummy/app/resources/book.rb +5 -0
  53. data/spec/dummy/app/resources/conference.rb +3 -0
  54. data/spec/dummy/app/resources/dog.rb +10 -0
  55. data/spec/dummy/app/resources/item.rb +5 -0
  56. data/spec/dummy/app/resources/meeting.rb +7 -0
  57. data/spec/dummy/app/resources/speaker.rb +3 -0
  58. data/spec/dummy/app/resources/state.rb +5 -0
  59. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  60. data/spec/dummy/config/application.rb +45 -0
  61. data/spec/dummy/config/boot.rb +10 -0
  62. data/spec/dummy/config/database.yml +22 -0
  63. data/spec/dummy/config/environment.rb +5 -0
  64. data/spec/dummy/config/environments/development.rb +26 -0
  65. data/spec/dummy/config/environments/production.rb +49 -0
  66. data/spec/dummy/config/environments/test.rb +35 -0
  67. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  68. data/spec/dummy/config/initializers/inflections.rb +10 -0
  69. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  70. data/spec/dummy/config/initializers/morpheus.rb +3 -0
  71. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  72. data/spec/dummy/config/initializers/session_store.rb +8 -0
  73. data/spec/dummy/config/locales/en.yml +5 -0
  74. data/spec/dummy/config/routes.rb +58 -0
  75. data/spec/dummy/config.ru +4 -0
  76. data/spec/dummy/db/migrate/20110605002144_create_purchases.rb +13 -0
  77. data/spec/dummy/db/test.sqlite3 +0 -0
  78. data/spec/dummy/public/404.html +26 -0
  79. data/spec/dummy/public/422.html +26 -0
  80. data/spec/dummy/public/500.html +26 -0
  81. data/spec/dummy/public/favicon.ico +0 -0
  82. data/spec/dummy/public/stylesheets/.gitkeep +0 -0
  83. data/spec/dummy/script/rails +6 -0
  84. data/spec/morpheus/associations/association_spec.rb +44 -0
  85. data/spec/morpheus/associations/belongs_to_association_spec.rb +5 -0
  86. data/spec/morpheus/associations/has_many_association_spec.rb +17 -0
  87. data/spec/morpheus/associations/has_one_association_spec.rb +5 -0
  88. data/spec/morpheus/base_spec.rb +126 -0
  89. data/spec/morpheus/client/associations_spec.rb +44 -0
  90. data/spec/morpheus/configuration_spec.rb +136 -0
  91. data/spec/morpheus/mixins/associations_spec.rb +141 -0
  92. data/spec/morpheus/mixins/attributes_spec.rb +99 -0
  93. data/spec/morpheus/mixins/conversion_spec.rb +76 -0
  94. data/spec/morpheus/mixins/finders_spec.rb +255 -0
  95. data/spec/morpheus/mixins/introspection_spec.rb +154 -0
  96. data/spec/morpheus/mixins/persistence_spec.rb +161 -0
  97. data/spec/morpheus/mixins/reflection_spec.rb +100 -0
  98. data/spec/morpheus/mixins/response_parsing_spec.rb +5 -0
  99. data/spec/morpheus/mock_spec.rb +133 -0
  100. data/spec/morpheus/relation_spec.rb +71 -0
  101. data/spec/morpheus/request_cache_spec.rb +5 -0
  102. data/spec/morpheus/request_spec.rb +5 -0
  103. data/spec/morpheus/response_spec.rb +73 -0
  104. data/spec/morpheus/type_caster_spec.rb +343 -0
  105. data/spec/shared/active_model_lint_test.rb +14 -0
  106. data/spec/spec_helper.rb +32 -0
  107. data/spec/support/configuration.rb +26 -0
  108. metadata +427 -0
@@ -0,0 +1,26 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The page you were looking for doesn't exist (404)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/404.html -->
21
+ <div class="dialog">
22
+ <h1>The page you were looking for doesn't exist.</h1>
23
+ <p>You may have mistyped the address or the page may have moved.</p>
24
+ </div>
25
+ </body>
26
+ </html>
@@ -0,0 +1,26 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The change you wanted was rejected (422)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/422.html -->
21
+ <div class="dialog">
22
+ <h1>The change you wanted was rejected.</h1>
23
+ <p>Maybe you tried to change something you didn't have access to.</p>
24
+ </div>
25
+ </body>
26
+ </html>
@@ -0,0 +1,26 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/500.html -->
21
+ <div class="dialog">
22
+ <h1>We're sorry, but something went wrong.</h1>
23
+ <p>We've been notified about this issue and we'll take a look at it shortly.</p>
24
+ </div>
25
+ </body>
26
+ </html>
File without changes
File without changes
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
+
4
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
5
+ require File.expand_path('../../config/boot', __FILE__)
6
+ require 'rails/commands'
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ describe Morpheus::Associations::Association, ".id" do
4
+
5
+ before(:each) do
6
+ meeting = Meeting.new(:id => 5, :title => "Rails Development")
7
+ Meeting.stub(:get).and_return(meeting)
8
+ end
9
+
10
+ it "calls the loaded target and retrieves it's id" do
11
+ @speaker = Speaker.new(:meeting_id => 5)
12
+ @speaker.meeting.id.should eql(5)
13
+ end
14
+
15
+ end
16
+
17
+ describe Morpheus::Associations::Association, ".loaded_target" do
18
+
19
+ before(:each) do
20
+ @meeting = Meeting.new(:id => 5, :title => "Rails Development")
21
+ end
22
+
23
+ it "loads target only once" do
24
+ Meeting.should_receive(:get).once.and_return(@meeting)
25
+ @speaker = Speaker.new(:meeting_id => 5)
26
+ @speaker.meeting.id
27
+ @speaker.meeting.id
28
+ end
29
+
30
+ end
31
+
32
+ describe Morpheus::Associations::Association, ".method_missing" do
33
+
34
+ before(:each) do
35
+ meeting = Meeting.new(:id => 5, :title => "Rails Development")
36
+ Meeting.stub(:get).and_return(meeting)
37
+ end
38
+
39
+ it "calls the loaded target and tries the method on the target" do
40
+ @speaker = Speaker.new(:meeting_id => 5)
41
+ @speaker.meeting.title
42
+ end
43
+
44
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe Morpheus::Associations::BelongsToAssociation, ".load_target!" do
4
+ pending
5
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe Morpheus::Associations::HasManyAssociation, ".load_target!" do
4
+ pending
5
+ end
6
+
7
+ describe Morpheus::Associations::HasManyAssociation, ".where" do
8
+ pending
9
+ end
10
+
11
+ describe Morpheus::Associations::HasManyAssociation, ".limit" do
12
+ pending
13
+ end
14
+
15
+ describe Morpheus::Associations::HasManyAssociation, ".page" do
16
+ pending
17
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe Morpheus::Associations::HasOneAssociation, ".load_target!" do
4
+ pending
5
+ end
@@ -0,0 +1,126 @@
1
+ require 'spec_helper'
2
+
3
+ describe Morpheus::Base, "ActiveModel Lint" do
4
+
5
+ let(:model_under_test) { Morpheus::Base.new }
6
+ it_behaves_like "ActiveModel"
7
+
8
+ end
9
+
10
+ describe Morpheus::Base, "implements Morpheus::Associations" do
11
+
12
+ it "includes the Morpheus::Associations module" do
13
+ Morpheus::Base.included_modules.should include(Morpheus::Associations)
14
+ end
15
+
16
+ end
17
+
18
+ describe Morpheus::Base, "implements Morpheus::Attributes" do
19
+
20
+ it "includes the Morpheus::Attributes module" do
21
+ Morpheus::Base.included_modules.should include(Morpheus::Attributes)
22
+ end
23
+
24
+ end
25
+
26
+ describe Morpheus::Base, "implements Morpheus::Conversion" do
27
+
28
+ it "includes the Morpheus::Finders module" do
29
+ Morpheus::Base.included_modules.should include(Morpheus::Conversion)
30
+ end
31
+
32
+ end
33
+
34
+ describe Morpheus::Base, "implements Morpheus::Finders" do
35
+
36
+ it "includes the Morpheus::Finders module" do
37
+ Morpheus::Base.included_modules.should include(Morpheus::Finders)
38
+ end
39
+
40
+ end
41
+
42
+ describe Morpheus::Base, "implements Morpheus::Introspection" do
43
+
44
+ it "includes the Morpheus::Finders module" do
45
+ Morpheus::Base.included_modules.should include(Morpheus::Introspection)
46
+ end
47
+
48
+ end
49
+
50
+ describe Morpheus::Base, "implements Morpheus::Persistence" do
51
+
52
+ it "includes the Morpheus::Persistence module" do
53
+ Morpheus::Base.included_modules.should include(Morpheus::Persistence)
54
+ end
55
+
56
+ end
57
+
58
+ describe Morpheus::Base, "implements Morpheus::ResponseParsing" do
59
+
60
+ it "includes the Morpheus::Finders module" do
61
+ Morpheus::Base.included_modules.should include(Morpheus::ResponseParsing)
62
+ end
63
+
64
+ end
65
+
66
+ describe Morpheus::Base, ".initialize" do
67
+
68
+ context "when no attributes hash is supplied" do
69
+
70
+ before(:each) do
71
+ @auto = Automobile.new
72
+ end
73
+
74
+ it "has attributes that are set to nil" do
75
+ @auto.attributes.should eql(HashWithIndifferentAccess.new({ :id => nil, :bhp => nil, :wheels => nil, :hybrid => nil, :name => nil }))
76
+ end
77
+
78
+ end
79
+
80
+ context "when an attributes hash is supplied" do
81
+
82
+ before(:each) do
83
+ @auto = Automobile.new(
84
+ :bhp => 300,
85
+ :wheels => 4,
86
+ :hybrid => false,
87
+ :name => "Roadster"
88
+ )
89
+ end
90
+
91
+ it "has attributes that are set to nil" do
92
+ @auto.attributes.should eql(HashWithIndifferentAccess.new({ :id => nil, :bhp => 300, :wheels => 4, :hybrid => false, :name => "Roadster" }))
93
+ end
94
+
95
+ end
96
+
97
+ end
98
+
99
+ describe Morpheus::Base, "defines an id property by default" do
100
+
101
+ it "defines setter and getter methods for the id property" do
102
+ base = Morpheus::Base.new(:id => 5)
103
+
104
+ Morpheus::Base.stub(:get).and_return(base)
105
+ @base = Morpheus::Base.find(1)
106
+ @base.should respond_to(:id)
107
+ @base.id.should eql(5)
108
+ end
109
+
110
+ it "creates an attribute entry for the id property" do
111
+ Morpheus::Base.new.attributes.should include(:id)
112
+ end
113
+
114
+ end
115
+
116
+ describe Morpheus::Base, ".==" do
117
+ pending
118
+ end
119
+
120
+ describe Morpheus::Base, "#base_class" do
121
+
122
+ it "returns the current class" do
123
+ Dog.base_class.should eql(Dog)
124
+ end
125
+
126
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ describe Morpheus::Client::Associations, "#belongs_to" do
4
+
5
+ it "defines a getter method" do
6
+ Purchase.new.should respond_to(:item)
7
+ end
8
+
9
+ it "defines a setter method" do
10
+ Purchase.new.should respond_to('item=')
11
+ end
12
+
13
+ context "when the belongs_to association is fulfilled by its contracted 'association_id' attribute" do
14
+
15
+ before(:each) do
16
+ item = Item.new(:id => 3)
17
+ Item.stub(:get).and_return(item)
18
+
19
+ @item = Item.find(3)
20
+ end
21
+
22
+ it "returns the association object when the id is specified" do
23
+ @purchase = Purchase.new
24
+ @purchase.item_id = 3
25
+ @purchase.item.should be_a(Item)
26
+ @purchase.item.id.should eql(3)
27
+ end
28
+
29
+ it 'can set an association directly' do
30
+ @purchase = Purchase.new
31
+ @purchase.item = @item
32
+ @purchase.item_id.should eql(3)
33
+ @purchase.item.should be_a(Item)
34
+ @purchase.item.id.should eql(3)
35
+ end
36
+
37
+ it "returns nil when the id is not specified" do
38
+ @purchase = Purchase.new
39
+ @purchase.item.should eql(nil)
40
+ end
41
+
42
+ end
43
+
44
+ end
@@ -0,0 +1,136 @@
1
+ require 'spec_helper'
2
+
3
+ describe Morpheus::Configuration, "#host" do
4
+
5
+ context "when host has not been set" do
6
+
7
+ before(:each) do
8
+ Morpheus::Configuration.host = nil
9
+ end
10
+
11
+ it "raises a ConfigurationError" do
12
+ lambda {
13
+ Morpheus::Configuration.host
14
+ }.should raise_error(Morpheus::ConfigurationError, "The request HOST has not been set. Please set the host using Morpheus::Configuration.host = 'http://www.example.com'")
15
+ end
16
+
17
+ end
18
+
19
+ context "when host has been set" do
20
+
21
+ before(:each) do
22
+ Morpheus::Configuration.host = "http://localhost:3000"
23
+ end
24
+
25
+ it "returns the host url string" do
26
+ Morpheus::Configuration.host.should eql("http://localhost:3000")
27
+ end
28
+
29
+ end
30
+
31
+ end
32
+
33
+ describe Morpheus::Configuration, "#hydra" do
34
+
35
+ context "when hydra has not been set" do
36
+
37
+ before(:each) do
38
+ Morpheus::Configuration.hydra = nil
39
+ end
40
+
41
+ it "returns the shared Hydra instance from Typhoeus" do
42
+ Morpheus::Configuration.hydra.should eql(Typhoeus::Hydra.hydra)
43
+ end
44
+
45
+ end
46
+
47
+ context "when hydra has been set" do
48
+
49
+ before(:each) do
50
+ @hydra = Typhoeus::Hydra.new
51
+ Morpheus::Configuration.hydra = @hydra
52
+ end
53
+
54
+ it "returns the specified Typhoeus Hydra instance" do
55
+ Morpheus::Configuration.hydra.should eql(@hydra)
56
+ end
57
+
58
+ end
59
+
60
+ end
61
+
62
+ describe Morpheus::Configuration, "#logger" do
63
+
64
+ before(:all) do
65
+ @original_logger = Morpheus::Configuration.logger
66
+ end
67
+
68
+ after(:all) do
69
+ Morpheus::Configuration.logger = @original_logger
70
+ end
71
+
72
+ context "when logger has not been set" do
73
+
74
+ before(:each) do
75
+ Morpheus::Configuration.logger = nil
76
+ end
77
+
78
+ it "returns the default Logger instance" do
79
+ Morpheus::Configuration.logger.should be_a(Logger)
80
+ end
81
+
82
+ end
83
+
84
+ context "when logger has been set" do
85
+
86
+ before(:each) do
87
+ @logger = Logger.new(STDOUT)
88
+ Morpheus::Configuration.logger = @logger
89
+ end
90
+
91
+ it "returns the specified Logger instance" do
92
+ Morpheus::Configuration.logger.should eql(@logger)
93
+ end
94
+
95
+ end
96
+
97
+ end
98
+
99
+ describe Morpheus::Configuration, "#allow_net_connect" do
100
+
101
+ it "disables all net connections through Typhoeus" do
102
+ Morpheus::Configuration.allow_net_connect = false
103
+ lambda {
104
+ Typhoeus::Request.get("http://localhost:3000")
105
+ }.should raise_error(Morpheus::NetConnectNotAllowedError)
106
+ end
107
+
108
+ end
109
+
110
+ describe Morpheus::Configuration, "#allow_net_connect?" do
111
+
112
+ context "when net connect is allowed" do
113
+
114
+ before(:each) do
115
+ Morpheus::Configuration.allow_net_connect = true
116
+ end
117
+
118
+ it "returns true" do
119
+ Morpheus::Configuration.should be_allow_net_connect
120
+ end
121
+
122
+ end
123
+
124
+ context "when net connect is not allowed" do
125
+
126
+ before(:each) do
127
+ Morpheus::Configuration.allow_net_connect = false
128
+ end
129
+
130
+ it "returns true" do
131
+ Morpheus::Configuration.should_not be_allow_net_connect
132
+ end
133
+
134
+ end
135
+
136
+ end
@@ -0,0 +1,141 @@
1
+ require 'spec_helper'
2
+
3
+ describe Morpheus::Associations, "#belongs_to" do
4
+
5
+ it "creates a property for this class matching association name, e.g. belong_to :author # => :author_id" do
6
+ Meeting.new.attributes.should include('conference_id')
7
+ end
8
+
9
+ it "defines a getter method" do
10
+ Meeting.new.should respond_to(:conference)
11
+ end
12
+
13
+ context "when the belongs_to association is fulfilled by its contracted 'association_id' attribute" do
14
+
15
+ before(:each) do
16
+ meeting = Meeting.new(:id => 1, :conference_id => 2)
17
+ meetings = [meeting]
18
+ conference = Conference.new(:id => 2)
19
+
20
+ Meeting.stub(:get) do |uri, params|
21
+ case uri
22
+ when '/meetings/1'
23
+ meeting
24
+ when '/meetings'
25
+ meetings
26
+ end
27
+ end
28
+ Conference.stub(:get).and_return(conference)
29
+
30
+ @meeting = Meeting.find(1)
31
+ end
32
+
33
+ it "returns the belongs_to association object" do
34
+ @conference = @meeting.conference
35
+ @conference.should be_a(Conference)
36
+ @conference.id.should eql(2)
37
+ @conference.meetings.should include(@meeting)
38
+ end
39
+
40
+ end
41
+
42
+ context "when the belongs_to association is fulfilled by its contracted 'association_id' attribute" do
43
+
44
+ before(:each) do
45
+ @meeting = Meeting.new
46
+ @meeting.conference_id = nil
47
+ end
48
+
49
+ it "returns nil" do
50
+ @meeting.conference.should be_nil
51
+ end
52
+
53
+ end
54
+
55
+ end
56
+
57
+ describe Morpheus::Associations, "#has_many" do
58
+
59
+ it "creates a getter method" do
60
+ Meeting.new.should respond_to(:attendees)
61
+ end
62
+
63
+ context "when the record has no id" do
64
+
65
+ before(:each) do
66
+ @meeting = Meeting.new
67
+ end
68
+
69
+ it "returns an empty array" do
70
+ @attendees = @meeting.attendees
71
+ @attendees.should be_an(Array)
72
+ @attendees.should be_empty
73
+ end
74
+
75
+ end
76
+
77
+ context "when the record has an id" do
78
+
79
+ before(:each) do
80
+ meeting = Meeting.new(:id => 1, :conference_id => 2)
81
+ attendees = [Attendee.new(:id => 2), Attendee.new(:id => 5)]
82
+
83
+ Meeting.stub(:get).and_return(meeting)
84
+ Attendee.stub(:get).and_return(attendees)
85
+
86
+ @meeting = Meeting.find(1)
87
+ end
88
+
89
+ it "returns the associated objects" do
90
+ @attendees = @meeting.attendees
91
+ @attendees.should be_an(Array)
92
+ @attendees.should have(2).attendees
93
+ @attendees.each do |attendee|
94
+ attendee.should be_a(Attendee)
95
+ end
96
+ end
97
+
98
+ end
99
+
100
+ end
101
+
102
+ describe Morpheus::Associations, "#has_one" do
103
+
104
+ it "creates a getter method" do
105
+ Meeting.new.should respond_to(:speaker)
106
+ end
107
+
108
+ context "when the record has no id" do
109
+
110
+ before(:each) do
111
+ @meeting = Meeting.new
112
+ end
113
+
114
+ it "returns nil" do
115
+ @meeting.speaker.should be_nil
116
+ end
117
+
118
+ end
119
+
120
+ context "when the record has an id" do
121
+
122
+ before(:each) do
123
+ meeting = Meeting.new(:id => 1, :conference_id => 2)
124
+ speakers = [Speaker.new(:id => 5, :meeting_id => 1)]
125
+
126
+ Meeting.stub(:get).and_return(meeting)
127
+ Speaker.stub(:get).and_return(speakers)
128
+
129
+ @meeting = Meeting.find(1)
130
+ end
131
+
132
+ it "returns the association object" do
133
+ @speaker = @meeting.speaker
134
+ @speaker.should be_a(Speaker)
135
+ @speaker.id.should eql(5)
136
+ @speaker.meeting.should == @meeting
137
+ end
138
+
139
+ end
140
+
141
+ end