ruby_odata 0.1.6 → 0.2.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +2 -0
- data/Guardfile +1 -1
- data/features/basic_auth.feature +13 -13
- data/features/cassettes/basic_auth_protected_resource.yml +22 -20
- data/features/cassettes/batch_request_additions.yml +26 -26
- data/features/cassettes/batch_request_deletes.yml +27 -27
- data/features/cassettes/batch_request_updates.yml +26 -26
- data/features/cassettes/clean_database_for_testing.yml +10 -10
- data/features/cassettes/cucumber_tags/basic_auth.yml +54 -163
- data/features/cassettes/cucumber_tags/batch_request.yml +229 -1118
- data/features/cassettes/cucumber_tags/complex_types.yml +81 -191
- data/features/cassettes/cucumber_tags/error_handling.yml +45 -33
- data/features/cassettes/cucumber_tags/query_builder.yml +555 -1248
- data/features/cassettes/cucumber_tags/service_manage.yml +216 -591
- data/features/cassettes/cucumber_tags/service_methods.yml +137 -412
- data/features/cassettes/cucumber_tags/ssl.yml +121 -117
- data/features/cassettes/cucumber_tags/type_conversion.yml +104 -170
- data/features/cassettes/service_manage_additions.yml +26 -28
- data/features/cassettes/service_manage_deletions.yml +21 -21
- data/features/cassettes/service_manage_deletions_2.yml +21 -21
- data/features/cassettes/unsecured_metadata.yml +14 -14
- data/features/service.feature +37 -37
- data/features/service_methods.feature +38 -38
- data/features/step_definitions/pickle_steps.rb +5 -5
- data/features/step_definitions/service_steps.rb +26 -26
- data/features/support/hooks.rb +3 -2
- data/features/support/vcr.rb +13 -13
- data/lib/ruby_odata.rb +4 -1
- data/lib/ruby_odata/association.rb +15 -8
- data/lib/ruby_odata/class_builder.rb +5 -1
- data/lib/ruby_odata/query_builder.rb +171 -173
- data/lib/ruby_odata/resource.rb +153 -0
- data/lib/ruby_odata/service.rb +30 -30
- data/lib/ruby_odata/version.rb +1 -1
- data/ruby_odata.gemspec +48 -43
- data/spec/association_spec.rb +15 -11
- data/spec/fixtures/decimal/metadata.xml +1 -0
- data/spec/fixtures/v4/edmx_metadata.xml +145 -0
- data/spec/fixtures/v4/result_categories.xml +0 -0
- data/spec/revised_service_spec.rb +16 -11
- data/spec/service_spec.rb +149 -114
- data/spec/service_v4_spec.rb +102 -0
- data/spec/spec_helper.rb +6 -1
- metadata +109 -32
- data/features/cassettes/cucumber_tags/service.yml +0 -234
@@ -0,0 +1,153 @@
|
|
1
|
+
module OData
|
2
|
+
class Resource
|
3
|
+
attr_reader :url, :options, :block
|
4
|
+
|
5
|
+
def initialize(url, options={}, backwards_compatibility=nil, &block)
|
6
|
+
@url = url
|
7
|
+
@block = block
|
8
|
+
@options = options.is_a?(Hash) ? options : { user: options, password: backwards_compatibility }
|
9
|
+
|
10
|
+
@conn = Faraday.new(url: url, ssl: { verify: verify_ssl }) do |faraday|
|
11
|
+
faraday.use :gzip
|
12
|
+
faraday.response :raise_error
|
13
|
+
faraday.adapter :excon
|
14
|
+
|
15
|
+
faraday.options.timeout = timeout if timeout
|
16
|
+
faraday.options.open_timeout = open_timeout if open_timeout
|
17
|
+
|
18
|
+
faraday.headers = (faraday.headers || {}).merge(@options[:headers] || {})
|
19
|
+
faraday.headers = (faraday.headers).merge({
|
20
|
+
:accept => '*/*; q=0.5, application/xml',
|
21
|
+
})
|
22
|
+
|
23
|
+
faraday.basic_auth user, password if user# this adds to headers so must be behind
|
24
|
+
end
|
25
|
+
|
26
|
+
@conn.headers[:user_agent] = 'Ruby'
|
27
|
+
end
|
28
|
+
|
29
|
+
def get(additional_headers={})
|
30
|
+
@conn.get do |req|
|
31
|
+
req.url url
|
32
|
+
req.headers = (headers || {}).merge(additional_headers)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def head(additional_headers={})
|
37
|
+
@conn.head do |req|
|
38
|
+
req.url url
|
39
|
+
req.headers = (headers || {}).merge(additional_headers)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def post(payload, additional_headers={})
|
44
|
+
@conn.post do |req|
|
45
|
+
req.url url
|
46
|
+
req.headers = (headers || {}).merge(additional_headers)
|
47
|
+
req.body = prepare_payload payload
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def put(payload, additional_headers={})
|
52
|
+
@conn.put do |req|
|
53
|
+
req.url url
|
54
|
+
req.headers = (headers || {}).merge(additional_headers)
|
55
|
+
req.body = prepare_payload payload
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def patch(payload, additional_headers={})
|
60
|
+
@conn.patch do |req|
|
61
|
+
req.url url
|
62
|
+
req.headers = (headers || {}).merge(additional_headers)
|
63
|
+
req.body = prepare_payload payload
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def delete(additional_headers={})
|
68
|
+
@conn.delete do |req|
|
69
|
+
req.url url
|
70
|
+
req.headers = (headers || {}).merge(additional_headers)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_s
|
75
|
+
url
|
76
|
+
end
|
77
|
+
|
78
|
+
def user
|
79
|
+
options[:user]
|
80
|
+
end
|
81
|
+
|
82
|
+
def password
|
83
|
+
options[:password]
|
84
|
+
end
|
85
|
+
|
86
|
+
def verify_ssl
|
87
|
+
options[:verify_ssl]
|
88
|
+
end
|
89
|
+
|
90
|
+
def headers
|
91
|
+
@conn.headers || {}
|
92
|
+
end
|
93
|
+
|
94
|
+
def timeout
|
95
|
+
options[:timeout]
|
96
|
+
end
|
97
|
+
|
98
|
+
def open_timeout
|
99
|
+
options[:open_timeout]
|
100
|
+
end
|
101
|
+
|
102
|
+
# Construct a subresource, preserving authentication.
|
103
|
+
#
|
104
|
+
# Example:
|
105
|
+
#
|
106
|
+
# site = RestClient::Resource.new('http://example.com', 'adam', 'mypasswd')
|
107
|
+
# site['posts/1/comments'].post 'Good article.', :content_type => 'text/plain'
|
108
|
+
#
|
109
|
+
# This is especially useful if you wish to define your site in one place and
|
110
|
+
# call it in multiple locations:
|
111
|
+
#
|
112
|
+
# def orders
|
113
|
+
# RestClient::Resource.new('http://example.com/orders', 'admin', 'mypasswd')
|
114
|
+
# end
|
115
|
+
#
|
116
|
+
# orders.get # GET http://example.com/orders
|
117
|
+
# orders['1'].get # GET http://example.com/orders/1
|
118
|
+
# orders['1/items'].delete # DELETE http://example.com/orders/1/items
|
119
|
+
#
|
120
|
+
# Nest resources as far as you want:
|
121
|
+
#
|
122
|
+
# site = RestClient::Resource.new('http://example.com')
|
123
|
+
# posts = site['posts']
|
124
|
+
# first_post = posts['1']
|
125
|
+
# comments = first_post['comments']
|
126
|
+
# comments.post 'Hello', :content_type => 'text/plain'
|
127
|
+
#
|
128
|
+
def [](suburl, &new_block)
|
129
|
+
case
|
130
|
+
when block_given? then self.class.new(concat_urls(url, suburl), options, &new_block)
|
131
|
+
when block then self.class.new(concat_urls(url, suburl), options, &block)
|
132
|
+
else
|
133
|
+
self.class.new(concat_urls(url, suburl), options)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def concat_urls(url, suburl) # :nodoc:
|
138
|
+
url = url.to_s
|
139
|
+
suburl = suburl.to_s
|
140
|
+
if url.slice(-1, 1) == '/' or suburl.slice(0, 1) == '/'
|
141
|
+
url + suburl
|
142
|
+
else
|
143
|
+
"#{url}/#{suburl}"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def prepare_payload payload
|
148
|
+
JSON.generate(payload)
|
149
|
+
rescue JSON::GeneratorError
|
150
|
+
payload
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
data/lib/ruby_odata/service.rb
CHANGED
@@ -9,7 +9,7 @@ class Service
|
|
9
9
|
# @option options [String] :username for http basic auth
|
10
10
|
# @option options [String] :password for http basic auth
|
11
11
|
# @option options [Object] :verify_ssl false if no verification, otherwise mode (OpenSSL::SSL::VERIFY_PEER is default)
|
12
|
-
# @option options [Hash] :rest_options a hash of rest-client options that will be passed to all
|
12
|
+
# @option options [Hash] :rest_options a hash of rest-client options that will be passed to all OData::Resource.new calls
|
13
13
|
# @option options [Hash] :additional_params a hash of query string params that will be passed on all calls
|
14
14
|
# @option options [Boolean, true] :eager_partial true if queries should consume partial feeds until the feed is complete, false if explicit calls to next must be performed
|
15
15
|
def initialize(service_uri, options = {})
|
@@ -97,12 +97,12 @@ class Service
|
|
97
97
|
# @raise [ServiceError] if there is an error when talking to the service
|
98
98
|
def execute
|
99
99
|
begin
|
100
|
-
@response =
|
100
|
+
@response = OData::Resource.new(build_query_uri, @rest_options).get
|
101
101
|
rescue Exception => e
|
102
102
|
handle_exception(e)
|
103
103
|
end
|
104
|
-
return Integer(@response) if @response =~ /^\d+$/
|
105
|
-
handle_collection_result(@response)
|
104
|
+
return Integer(@response.body) if @response.body =~ /^\d+$/
|
105
|
+
handle_collection_result(@response.body)
|
106
106
|
end
|
107
107
|
|
108
108
|
# Overridden to identify methods handled by method_missing
|
@@ -147,8 +147,8 @@ class Service
|
|
147
147
|
raise NotSupportedError, "You cannot load a property on an entity that isn't tracked" if obj.send(:__metadata).nil?
|
148
148
|
raise ArgumentError, "'#{nav_prop}' is not a valid navigation property" unless obj.respond_to?(nav_prop.to_sym)
|
149
149
|
raise ArgumentError, "'#{nav_prop}' is not a valid navigation property" unless @class_metadata[obj.class.to_s][nav_prop].nav_prop
|
150
|
-
results =
|
151
|
-
prop_results = build_classes_from_result(results)
|
150
|
+
results = OData::Resource.new(build_load_property_uri(obj, nav_prop), @rest_options).get
|
151
|
+
prop_results = build_classes_from_result(results.body)
|
152
152
|
obj.send "#{nav_prop}=", (singular?(nav_prop) ? prop_results.first : prop_results)
|
153
153
|
end
|
154
154
|
|
@@ -224,7 +224,7 @@ class Service
|
|
224
224
|
@rest_options.merge!(options[:rest_options] || {})
|
225
225
|
@additional_params = options[:additional_params] || {}
|
226
226
|
@namespace = options[:namespace]
|
227
|
-
@json_type = options[:json_type] ||
|
227
|
+
@json_type = options[:json_type] || 'application/json'
|
228
228
|
end
|
229
229
|
|
230
230
|
def default_instance_vars!
|
@@ -236,7 +236,7 @@ class Service
|
|
236
236
|
end
|
237
237
|
|
238
238
|
def set_namespaces
|
239
|
-
@edmx = Nokogiri::XML(
|
239
|
+
@edmx = Nokogiri::XML(OData::Resource.new(build_metadata_uri, @rest_options).get.body)
|
240
240
|
@ds_namespaces = {
|
241
241
|
"m" => "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata",
|
242
242
|
"edmx" => "http://schemas.microsoft.com/ado/2007/06/edmx",
|
@@ -376,8 +376,8 @@ class Service
|
|
376
376
|
def handle_exception(e)
|
377
377
|
raise e unless defined? e.response
|
378
378
|
|
379
|
-
code = e.
|
380
|
-
error = Nokogiri::XML(e.response)
|
379
|
+
code = e.response[:status]
|
380
|
+
error = Nokogiri::XML(e.response[:body])
|
381
381
|
|
382
382
|
message = if error.xpath("m:error/m:message", @ds_namespaces).first
|
383
383
|
error.xpath("m:error/m:message", @ds_namespaces).first.content
|
@@ -509,8 +509,8 @@ class Service
|
|
509
509
|
|
510
510
|
def handle_partial
|
511
511
|
if @next_uri
|
512
|
-
result =
|
513
|
-
results = handle_collection_result(result)
|
512
|
+
result = OData::Resource.new(@next_uri, @rest_options).get
|
513
|
+
results = handle_collection_result(result.body)
|
514
514
|
end
|
515
515
|
results
|
516
516
|
end
|
@@ -600,26 +600,26 @@ class Service
|
|
600
600
|
if operation.kind == "Add"
|
601
601
|
save_uri = build_save_uri(operation)
|
602
602
|
json_klass = operation.klass.to_json(:type => :add)
|
603
|
-
post_result =
|
604
|
-
return build_classes_from_result(post_result)
|
603
|
+
post_result = OData::Resource.new(save_uri, @rest_options).post json_klass, {:content_type => @json_type}
|
604
|
+
return build_classes_from_result(post_result.body)
|
605
605
|
elsif operation.kind == "Update"
|
606
606
|
update_uri = build_resource_uri(operation)
|
607
607
|
json_klass = operation.klass.to_json
|
608
|
-
update_result =
|
609
|
-
return (update_result.
|
608
|
+
update_result = OData::Resource.new(update_uri, @rest_options).put json_klass, {:content_type => @json_type}
|
609
|
+
return (update_result.status == 204)
|
610
610
|
elsif operation.kind == "Delete"
|
611
611
|
delete_uri = build_resource_uri(operation)
|
612
|
-
delete_result =
|
613
|
-
return (delete_result.
|
612
|
+
delete_result = OData::Resource.new(delete_uri, @rest_options).delete
|
613
|
+
return (delete_result.status == 204)
|
614
614
|
elsif operation.kind == "AddLink"
|
615
615
|
save_uri = build_add_link_uri(operation)
|
616
616
|
json_klass = operation.child_klass.to_json(:type => :link)
|
617
|
-
post_result =
|
617
|
+
post_result = OData::Resource.new(save_uri, @rest_options).post json_klass, {:content_type => @json_type}
|
618
618
|
|
619
619
|
# Attach the child to the parent
|
620
|
-
link_child_to_parent(operation) if (post_result.
|
620
|
+
link_child_to_parent(operation) if (post_result.status == 204)
|
621
621
|
|
622
|
-
return(post_result.
|
622
|
+
return(post_result.status == 204)
|
623
623
|
end
|
624
624
|
end
|
625
625
|
|
@@ -633,11 +633,11 @@ class Service
|
|
633
633
|
batch_uri = build_batch_uri
|
634
634
|
|
635
635
|
body = build_batch_body(operations, batch_num, changeset_num)
|
636
|
-
result =
|
636
|
+
result = OData::Resource.new( batch_uri, @rest_options).post body, {:content_type => "multipart/mixed; boundary=batch_#{batch_num}"}
|
637
637
|
|
638
638
|
# TODO: More result validation needs to be done.
|
639
639
|
# The result returns HTTP 202 even if there is an error in the batch
|
640
|
-
return (result.
|
640
|
+
return (result.status == 202)
|
641
641
|
end
|
642
642
|
def build_batch_body(operations, batch_num, changeset_num)
|
643
643
|
# Header
|
@@ -827,17 +827,17 @@ class Service
|
|
827
827
|
func[:parameters].keys.each_with_index { |key, i| params[key] = args[0][i] } unless func[:parameters].nil?
|
828
828
|
|
829
829
|
function_uri = build_function_import_uri(name, params)
|
830
|
-
result =
|
830
|
+
result = OData::Resource.new(function_uri, @rest_options).send(func[:http_method].downcase, {})
|
831
831
|
|
832
832
|
# Is this a 204 (No content) result?
|
833
|
-
return true if result.
|
833
|
+
return true if result.status == 204
|
834
834
|
|
835
835
|
# No? Then we need to parse the results. There are 4 kinds...
|
836
836
|
if func[:return_type] == Array
|
837
837
|
# a collection of entites
|
838
|
-
return build_classes_from_result(result) if @classes.include?(func[:inner_return_type].to_s)
|
838
|
+
return build_classes_from_result(result.body) if @classes.include?(func[:inner_return_type].to_s)
|
839
839
|
# a collection of native types
|
840
|
-
elements = Nokogiri::XML(result).xpath("//ds:element", @ds_namespaces)
|
840
|
+
elements = Nokogiri::XML(result.body).xpath("//ds:element", @ds_namespaces)
|
841
841
|
results = []
|
842
842
|
elements.each do |e|
|
843
843
|
results << parse_primative_type(e.content, func[:inner_return_type])
|
@@ -847,18 +847,18 @@ class Service
|
|
847
847
|
|
848
848
|
# a single entity
|
849
849
|
if @classes.include?(func[:return_type].to_s)
|
850
|
-
entry = Nokogiri::XML(result).xpath("atom:entry[not(ancestor::atom:entry)]", @ds_namespaces)
|
850
|
+
entry = Nokogiri::XML(result.body).xpath("atom:entry[not(ancestor::atom:entry)]", @ds_namespaces)
|
851
851
|
return entry_to_class(entry)
|
852
852
|
end
|
853
853
|
|
854
854
|
# or a single native type
|
855
855
|
unless func[:return_type].nil?
|
856
|
-
e = Nokogiri::XML(result).xpath("/*").first
|
856
|
+
e = Nokogiri::XML(result.body).xpath("/*").first
|
857
857
|
return parse_primative_type(e.content, func[:return_type])
|
858
858
|
end
|
859
859
|
|
860
860
|
# Nothing could be parsed, so just return if we got a 200 or not
|
861
|
-
return (result.
|
861
|
+
return (result.status == 200)
|
862
862
|
end
|
863
863
|
|
864
864
|
# Helpers
|
data/lib/ruby_odata/version.rb
CHANGED
data/ruby_odata.gemspec
CHANGED
@@ -1,43 +1,48 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
|
-
$:.push File.expand_path("../lib", __FILE__)
|
3
|
-
require "ruby_odata/version"
|
4
|
-
|
5
|
-
Gem::Specification.new do |s|
|
6
|
-
s.name = "ruby_odata"
|
7
|
-
s.version = OData::VERSION
|
8
|
-
s.platform = Gem::Platform::RUBY
|
9
|
-
s.authors = ["Damien White"]
|
10
|
-
s.email = ["damien.white@visoftinc.com"]
|
11
|
-
s.homepage = %q{http://github.com/visoft/ruby_odata}
|
12
|
-
s.summary = %q{Ruby consumer of OData services.}
|
13
|
-
s.description = %q{An OData Client Library for Ruby. Use this to interact with OData services}
|
14
|
-
s.license = "MIT"
|
15
|
-
|
16
|
-
s.rubyforge_project = "ruby-odata"
|
17
|
-
|
18
|
-
s.required_ruby_version = '>= 1.9.3'
|
19
|
-
|
20
|
-
s.add_dependency("addressable", ">= 2.3.4")
|
21
|
-
s.add_dependency("i18n", "
|
22
|
-
s.add_dependency("activesupport", ">= 3.0.0")
|
23
|
-
s.add_dependency("
|
24
|
-
s.add_dependency("
|
25
|
-
|
26
|
-
s.
|
27
|
-
|
28
|
-
s.add_development_dependency("
|
29
|
-
s.add_development_dependency("
|
30
|
-
s.add_development_dependency("
|
31
|
-
s.add_development_dependency("
|
32
|
-
s.add_development_dependency("
|
33
|
-
s.add_development_dependency("
|
34
|
-
s.add_development_dependency("
|
35
|
-
s.add_development_dependency("
|
36
|
-
s.add_development_dependency("
|
37
|
-
s.add_development_dependency("
|
38
|
-
|
39
|
-
s.
|
40
|
-
s.
|
41
|
-
s.
|
42
|
-
s.
|
43
|
-
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "ruby_odata/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "ruby_odata"
|
7
|
+
s.version = OData::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Damien White"]
|
10
|
+
s.email = ["damien.white@visoftinc.com"]
|
11
|
+
s.homepage = %q{http://github.com/visoft/ruby_odata}
|
12
|
+
s.summary = %q{Ruby consumer of OData services.}
|
13
|
+
s.description = %q{An OData Client Library for Ruby. Use this to interact with OData services}
|
14
|
+
s.license = "MIT"
|
15
|
+
|
16
|
+
s.rubyforge_project = "ruby-odata"
|
17
|
+
|
18
|
+
s.required_ruby_version = '>= 1.9.3'
|
19
|
+
|
20
|
+
s.add_dependency("addressable", ">= 2.3.4")
|
21
|
+
s.add_dependency("i18n", ">= 0.7.0")
|
22
|
+
s.add_dependency("activesupport", ">= 3.0.0")
|
23
|
+
s.add_dependency("excon", "~> 0.45.3")
|
24
|
+
s.add_dependency("faraday_middleware")
|
25
|
+
s.add_dependency("faraday", "~> 0.9.1")
|
26
|
+
s.add_dependency("nokogiri", ">= 1.4.2")
|
27
|
+
|
28
|
+
s.add_development_dependency("rake", ">=0.9.2")
|
29
|
+
s.add_development_dependency("rspec", "~> 3.2.0")
|
30
|
+
s.add_development_dependency("rspec-its", "~> 1.2.0")
|
31
|
+
s.add_development_dependency("cucumber", "~> 2.0.0")
|
32
|
+
s.add_development_dependency("pickle", "~> 0.5.1")
|
33
|
+
s.add_development_dependency("machinist", "~> 2.0")
|
34
|
+
s.add_development_dependency("webmock", "~> 1.21.0")
|
35
|
+
s.add_development_dependency("guard", "~> 2.12.5")
|
36
|
+
s.add_development_dependency("guard-rspec", "~> 4.5.0")
|
37
|
+
s.add_development_dependency("guard-cucumber", "~> 1.6.0")
|
38
|
+
s.add_development_dependency("vcr", "~> 2.9.3")
|
39
|
+
s.add_development_dependency("simplecov", "~> 0.7.1")
|
40
|
+
s.add_development_dependency("coveralls", "~> 0.6.7")
|
41
|
+
s.add_development_dependency("pry")
|
42
|
+
s.add_development_dependency("pry-nav")
|
43
|
+
|
44
|
+
s.files = `git ls-files`.split("\n")
|
45
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
46
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
47
|
+
s.require_paths = ["lib"]
|
48
|
+
end
|
data/spec/association_spec.rb
CHANGED
@@ -4,7 +4,7 @@ module OData
|
|
4
4
|
describe Association do
|
5
5
|
before(:all) do
|
6
6
|
stub_request(:get, /http:\/\/test\.com\/test\.svc\/\$metadata(?:\?.+)?/).
|
7
|
-
with(:headers =>
|
7
|
+
with(:headers => DEFAULT_HEADERS).
|
8
8
|
to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/sample_service/edmx_categories_products.xml", __FILE__)), :headers => {})
|
9
9
|
|
10
10
|
@svc = OData::Service.new "http://test.com/test.svc/$metadata"
|
@@ -13,33 +13,37 @@ module OData
|
|
13
13
|
describe "#initialize singlular navigation property" do
|
14
14
|
before { @association = Association.new @product_category, @svc.edmx }
|
15
15
|
subject { @association }
|
16
|
-
|
17
|
-
it "
|
16
|
+
|
17
|
+
it "sets the association name" do
|
18
18
|
subject.name.should eq 'Category_Products'
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
|
+
it "sets the association namespace" do
|
21
22
|
subject.namespace.should eq 'RubyODataService'
|
22
23
|
end
|
23
|
-
|
24
|
+
|
25
|
+
it "sets the relationship name" do
|
24
26
|
subject.relationship.should eq 'RubyODataService.Category_Products'
|
25
27
|
end
|
28
|
+
|
26
29
|
context "from_role method" do
|
27
30
|
subject { @association.from_role }
|
28
|
-
it { should have_key 'Category_Products_Target'}
|
29
|
-
it "
|
31
|
+
it { should have_key 'Category_Products_Target'}
|
32
|
+
it "sets the edmx type" do
|
30
33
|
subject['Category_Products_Target'][:edmx_type].should eq 'RubyODataService.Product'
|
31
34
|
end
|
32
|
-
it "
|
35
|
+
it "sets the multiplicity" do
|
33
36
|
subject['Category_Products_Target'][:multiplicity].should eq '*'
|
34
37
|
end
|
35
38
|
end
|
39
|
+
|
36
40
|
context "to_role method" do
|
37
41
|
subject { @association.to_role }
|
38
|
-
it { should have_key 'Category_Products_Source'}
|
39
|
-
it "
|
42
|
+
it { should have_key 'Category_Products_Source'}
|
43
|
+
it "sets the edmx type" do
|
40
44
|
subject['Category_Products_Source'][:edmx_type].should eq 'RubyODataService.Category'
|
41
45
|
end
|
42
|
-
it "
|
46
|
+
it "sets the multiplicity" do
|
43
47
|
subject['Category_Products_Source'][:multiplicity].should eq '1'
|
44
48
|
end
|
45
49
|
end
|