odata 0.0.10 → 0.1.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +5 -5
- data/lib/odata.rb +5 -1
- data/lib/odata/entity.rb +71 -3
- data/lib/odata/entity_set.rb +45 -1
- data/lib/odata/properties/date_time.rb +3 -1
- data/lib/odata/property.rb +4 -0
- data/lib/odata/service.rb +46 -55
- data/lib/odata/version.rb +1 -1
- data/odata.gemspec +1 -0
- data/spec/fixtures/sample_service/first_product.xml +42 -0
- data/spec/fixtures/sample_service/product_9999.xml +34 -0
- data/spec/odata/entity_set_spec.rb +62 -2
- data/spec/odata/entity_spec.rb +3 -0
- data/spec/odata/service_spec.rb +0 -21
- data/spec/spec_helper.rb +6 -0
- metadata +21 -7
- data/lib/odata/model.rb +0 -116
- data/spec/examples/product_model.rb +0 -13
- data/spec/odata/model_spec.rb +0 -25
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a62f54f63a4c6c397d711b31eea1d31f41383e80
|
|
4
|
+
data.tar.gz: 8a4e945b39e401bfbaaaba43e2e52c884949318a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 591263ed5f45b8f12ef3ebf167bed9fff9e3e61c98de34b58601a5c3db2b89f18c4207feabbdccf08d9970a67c93f0f2d340747b7f767f64a615255c54769735
|
|
7
|
+
data.tar.gz: 4bc3b99da624d26e44d77ff8400c1ae5067d77aa56a8f435f739b37de0d50de3dc28967e8aae3fce004491e00808167fdd022133d2d25782347b28296d698cc3
|
data/CHANGELOG.md
ADDED
data/README.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# OData
|
|
2
2
|
|
|
3
|
-
[](https://travis-ci.org/ruby-odata/odata)
|
|
4
|
+
[](https://codeclimate.com/github/ruby-odata/odata)
|
|
5
|
+
[](https://codeclimate.com/github/ruby-odata/odata)
|
|
6
6
|
[](http://badge.fury.io/rb/odata)
|
|
7
|
-
[](https://gemnasium.com/ruby-odata/odata)
|
|
8
|
+
[](http://rubydoc.info/github/ruby-odata/odata/master/frames)
|
|
9
9
|
|
|
10
10
|
The OData gem provides a simple wrapper around the OData API protocol. It has
|
|
11
11
|
the ability to automatically inspect compliant APIs and expose the relevant
|
data/lib/odata.rb
CHANGED
|
@@ -9,14 +9,18 @@ require 'active_support/core_ext'
|
|
|
9
9
|
require 'active_support/concern'
|
|
10
10
|
|
|
11
11
|
require 'odata/version'
|
|
12
|
+
require 'odata/property'
|
|
13
|
+
require 'odata/properties'
|
|
12
14
|
require 'odata/entity'
|
|
13
15
|
require 'odata/entity_set'
|
|
14
16
|
require 'odata/service'
|
|
15
17
|
require 'odata/service_registry'
|
|
16
|
-
require 'odata/model'
|
|
17
18
|
|
|
18
19
|
require 'odata/railtie' if defined?(::Rails)
|
|
19
20
|
|
|
21
|
+
# The OData gem provides a convenient way to interact with OData services from
|
|
22
|
+
# Ruby. Please look to the {file:README.md README} for how to get started using
|
|
23
|
+
# the OData gem.
|
|
20
24
|
module OData
|
|
21
25
|
# Your code goes here...
|
|
22
26
|
end
|
data/lib/odata/entity.rb
CHANGED
|
@@ -5,7 +5,6 @@ module OData
|
|
|
5
5
|
def initialize(options = {})
|
|
6
6
|
@type = options[:type]
|
|
7
7
|
@namespace = options[:namespace]
|
|
8
|
-
@properties = {}
|
|
9
8
|
end
|
|
10
9
|
|
|
11
10
|
def name
|
|
@@ -13,7 +12,34 @@ module OData
|
|
|
13
12
|
end
|
|
14
13
|
|
|
15
14
|
def [](property_name)
|
|
16
|
-
|
|
15
|
+
begin
|
|
16
|
+
properties[property_name.to_s].value
|
|
17
|
+
rescue NoMethodError
|
|
18
|
+
raise ArgumentError, "Unknown property: #{property_name}"
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def []=(property_name, value)
|
|
23
|
+
begin
|
|
24
|
+
properties[property_name.to_s].value = value
|
|
25
|
+
rescue NoMethodError
|
|
26
|
+
raise ArgumentError, "Unknown property: #{property_name}"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.with_properties(new_properties = {}, options = {})
|
|
31
|
+
entity = OData::Entity.new(options)
|
|
32
|
+
entity.instance_eval do
|
|
33
|
+
# TODO Define the properties
|
|
34
|
+
service.properties_for(name).each do |name, instance|
|
|
35
|
+
set_property(name, instance)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
new_properties.each do |property_name, property_value|
|
|
39
|
+
self[property_name] = property_value
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
entity
|
|
17
43
|
end
|
|
18
44
|
|
|
19
45
|
def self.from_xml(xml_doc, options = {})
|
|
@@ -55,14 +81,56 @@ module OData
|
|
|
55
81
|
entity
|
|
56
82
|
end
|
|
57
83
|
|
|
84
|
+
def to_xml
|
|
85
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
|
86
|
+
xml.entry('xmlns' => 'http://www.w3.org/2005/Atom',
|
|
87
|
+
'xmlns:data' => 'http://schemas.microsoft.com/ado/2007/08/dataservices',
|
|
88
|
+
'xmlns:metadata' => 'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata',
|
|
89
|
+
'xmlns:georss' => 'http://www.georss.org/georss',
|
|
90
|
+
'xmlns:gml' => 'http://www.opengis.net/gml',
|
|
91
|
+
'xml:base' => 'http://services.odata.org/OData/OData.svc/') do
|
|
92
|
+
xml.category(term: "#{namespace}.#{type}",
|
|
93
|
+
scheme: 'http://schemas.microsoft.com/ado/2007/08/dataservices/scheme')
|
|
94
|
+
xml.author { xml.name }
|
|
95
|
+
|
|
96
|
+
xml.content(type: 'application/xml') do
|
|
97
|
+
xml['metadata'].properties do
|
|
98
|
+
properties.each do |name, property|
|
|
99
|
+
next if name == primary_key
|
|
100
|
+
attributes = {
|
|
101
|
+
'metadata:type' => property.type,
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if property.value.nil?
|
|
105
|
+
attributes['metadata:null'] = 'true'
|
|
106
|
+
xml['data'].send(name.to_sym, attributes)
|
|
107
|
+
else
|
|
108
|
+
xml['data'].send(name.to_sym, attributes, property.xml_value)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
builder.to_xml
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def primary_key
|
|
119
|
+
service.primary_key_for(name)
|
|
120
|
+
end
|
|
121
|
+
|
|
58
122
|
private
|
|
59
123
|
|
|
124
|
+
def properties
|
|
125
|
+
@properties ||= {}
|
|
126
|
+
end
|
|
127
|
+
|
|
60
128
|
def service
|
|
61
129
|
@service ||= OData::ServiceRegistry[namespace]
|
|
62
130
|
end
|
|
63
131
|
|
|
64
132
|
def set_property(name, odata_property)
|
|
65
|
-
|
|
133
|
+
properties[name.to_s] = odata_property.dup
|
|
66
134
|
end
|
|
67
135
|
end
|
|
68
136
|
end
|
data/lib/odata/entity_set.rb
CHANGED
|
@@ -39,7 +39,7 @@ module OData
|
|
|
39
39
|
page_position = 0
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
-
entity = OData::Entity.from_xml(entities[page_position],
|
|
42
|
+
entity = OData::Entity.from_xml(entities[page_position], entity_options)
|
|
43
43
|
block_given? ? block.call(entity) : yield(entity)
|
|
44
44
|
|
|
45
45
|
counter += 1
|
|
@@ -47,17 +47,61 @@ module OData
|
|
|
47
47
|
end
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
+
def first
|
|
51
|
+
result = service.execute("#{name}?$skip=0&$top=1")
|
|
52
|
+
entities = service.find_entities(result)
|
|
53
|
+
OData::Entity.from_xml(entities[0], entity_options)
|
|
54
|
+
end
|
|
55
|
+
|
|
50
56
|
# Returns the number of entities within the set
|
|
51
57
|
def count
|
|
52
58
|
service.execute("#{name}/$count").body.to_i
|
|
53
59
|
end
|
|
54
60
|
|
|
61
|
+
def new_entity(properties = {})
|
|
62
|
+
OData::Entity.with_properties(properties, entity_options)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def <<(entity)
|
|
66
|
+
new_entity = entity[entity.primary_key].nil?
|
|
67
|
+
|
|
68
|
+
url_chunk = name
|
|
69
|
+
url_chunk += "(#{entity[entity.primary_key]})" unless new_entity
|
|
70
|
+
|
|
71
|
+
options = {
|
|
72
|
+
method: :post,
|
|
73
|
+
body: entity.to_xml.gsub(/\n\s+/, ''),
|
|
74
|
+
headers: {
|
|
75
|
+
Accept: 'application/atom+xml',
|
|
76
|
+
'Content-Type' => 'application/atom+xml'
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
result = service.execute(url_chunk, options)
|
|
81
|
+
if result.code.to_s =~ /^2[0-9][0-9]$/
|
|
82
|
+
if new_entity
|
|
83
|
+
doc = ::Nokogiri::XML(result.body).remove_namespaces!
|
|
84
|
+
entity[entity.primary_key] = doc.xpath("//content/properties/#{entity.primary_key}").first.content
|
|
85
|
+
end
|
|
86
|
+
else
|
|
87
|
+
raise StandardError, 'Something went wrong committing your entity'
|
|
88
|
+
end
|
|
89
|
+
entity
|
|
90
|
+
end
|
|
91
|
+
|
|
55
92
|
private
|
|
56
93
|
|
|
57
94
|
def service
|
|
58
95
|
@service ||= OData::ServiceRegistry[namespace]
|
|
59
96
|
end
|
|
60
97
|
|
|
98
|
+
def entity_options
|
|
99
|
+
{
|
|
100
|
+
namespace: namespace,
|
|
101
|
+
type: type
|
|
102
|
+
}
|
|
103
|
+
end
|
|
104
|
+
|
|
61
105
|
def get_paginated_entities(per_page, page)
|
|
62
106
|
result = service.execute("#{name}?$inlinecount=allpages&$skip=#{per_page * page}&$top=#{per_page}")
|
|
63
107
|
entities = service.find_entities(result)
|
|
@@ -26,14 +26,16 @@ module OData
|
|
|
26
26
|
|
|
27
27
|
def validate(value)
|
|
28
28
|
begin
|
|
29
|
+
return if value.nil? && allows_nil?
|
|
29
30
|
return if value.is_a?(::DateTime)
|
|
30
31
|
::DateTime.strptime(value, '%Y-%m-%dT%H:%M:%S.%L')
|
|
31
|
-
rescue
|
|
32
|
+
rescue
|
|
32
33
|
raise ArgumentError, 'Value is not a date time format that can be parsed'
|
|
33
34
|
end
|
|
34
35
|
end
|
|
35
36
|
|
|
36
37
|
def parse_value(value)
|
|
38
|
+
return value if value.nil? && allows_nil?
|
|
37
39
|
parsed_value = value
|
|
38
40
|
parsed_value = ::DateTime.parse(value) unless value.is_a?(::DateTime)
|
|
39
41
|
parsed_value.strftime('%Y-%m-%dT%H:%M:%S.%L')
|
data/lib/odata/property.rb
CHANGED
data/lib/odata/service.rb
CHANGED
|
@@ -61,27 +61,9 @@ module OData
|
|
|
61
61
|
"#<#{self.class.name}:#{self.object_id} namespace='#{self.namespace}' service_url='#{self.service_url}'>"
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
-
# Handles getting OData resources from the service.
|
|
65
|
-
#
|
|
66
|
-
# @param model [OData::Model] the type of resource being requested
|
|
67
|
-
# @param criteria [Hash] any criteria to narrow the request
|
|
68
|
-
# @return [Array] instances of the requested model
|
|
69
|
-
def get(model, criteria = {})
|
|
70
|
-
request = ::Typhoeus::Request.new(
|
|
71
|
-
build_request_url(model, criteria),
|
|
72
|
-
options[:typhoeus].merge({
|
|
73
|
-
method: :get
|
|
74
|
-
})
|
|
75
|
-
)
|
|
76
|
-
request.run
|
|
77
|
-
response = request.response
|
|
78
|
-
feed = ::Nokogiri::XML(response.body).remove_namespaces!
|
|
79
|
-
feed.xpath('//entry').collect {|entry| parse_model_from_feed(model, entry)}
|
|
80
|
-
end
|
|
81
|
-
|
|
82
64
|
# Retrieves the EntitySet associated with a specific EntityType by name
|
|
83
65
|
#
|
|
84
|
-
# @param
|
|
66
|
+
# @param entity_set_name [to_s] the name of the EntitySet desired
|
|
85
67
|
# @return [OData::EntitySet] an OData::EntitySet to query
|
|
86
68
|
def [](entity_set_name)
|
|
87
69
|
xpath_query = "//EntityContainer/EntitySet[@Name='#{entity_set_name}']"
|
|
@@ -95,6 +77,11 @@ module OData
|
|
|
95
77
|
container: container_name)
|
|
96
78
|
end
|
|
97
79
|
|
|
80
|
+
# Execute a request against the service
|
|
81
|
+
#
|
|
82
|
+
# @param url_chunk [to_s] string to append to service url
|
|
83
|
+
# @param additional_options [Hash] options to pass to Typhoeus
|
|
84
|
+
# @return [Typhoeus::Response]
|
|
98
85
|
def execute(url_chunk, additional_options = {})
|
|
99
86
|
request = ::Typhoeus::Request.new(
|
|
100
87
|
"#{service_url}/#{url_chunk}",
|
|
@@ -106,30 +93,70 @@ module OData
|
|
|
106
93
|
request.response
|
|
107
94
|
end
|
|
108
95
|
|
|
96
|
+
# Find a specific node in the given result set
|
|
97
|
+
#
|
|
98
|
+
# @param results [Typhoeus::Response]
|
|
99
|
+
# @return [Nokogiri::XML::Element]
|
|
109
100
|
def find_node(results, node_name)
|
|
110
101
|
document = ::Nokogiri::XML(results.body)
|
|
111
102
|
document.remove_namespaces!
|
|
112
103
|
document.xpath("//#{node_name}").first
|
|
113
104
|
end
|
|
114
105
|
|
|
106
|
+
# Find entity entries in a result set
|
|
107
|
+
#
|
|
108
|
+
# @param results [Typhoeus::Response]
|
|
109
|
+
# @return [Nokogiri::XML::NodeSet]
|
|
115
110
|
def find_entities(results)
|
|
116
111
|
document = ::Nokogiri::XML(results.body)
|
|
117
112
|
document.remove_namespaces!
|
|
118
113
|
document.xpath('//entry')
|
|
119
114
|
end
|
|
120
115
|
|
|
116
|
+
# Get the property type for an entity from metadata.
|
|
117
|
+
#
|
|
118
|
+
# @param entity_name [to_s] the name of the relevant entity
|
|
119
|
+
# @param property_name [to_s] the property name needed
|
|
120
|
+
# @return [String] the name of the property's type
|
|
121
121
|
def get_property_type(entity_name, property_name)
|
|
122
122
|
metadata.xpath("//EntityType[@Name='#{entity_name}']/Property[@Name='#{property_name}']").first.attributes['Type'].value
|
|
123
123
|
end
|
|
124
124
|
|
|
125
|
+
# Get the property used as the title for an entity from metadata.
|
|
126
|
+
#
|
|
127
|
+
# @param entity_name [to_s] the name of the relevant entity
|
|
128
|
+
# @return [String] the name of the property used as the entity title
|
|
125
129
|
def get_title_property_name(entity_name)
|
|
126
130
|
metadata.xpath("//EntityType[@Name='#{entity_name}']/Property[@FC_TargetPath='SyndicationTitle']").first.attributes['Name'].value
|
|
127
131
|
end
|
|
128
132
|
|
|
133
|
+
# Get the property used as the summary for an entity from metadata.
|
|
134
|
+
#
|
|
135
|
+
# @param entity_name [to_s] the name of the relevant entity
|
|
136
|
+
# @return [String] the name of the property used as the entity summary
|
|
129
137
|
def get_summary_property_name(entity_name)
|
|
130
138
|
metadata.xpath("//EntityType[@Name='#{entity_name}']/Property[@FC_TargetPath='SyndicationSummary']").first.attributes['Name'].value
|
|
131
139
|
end
|
|
132
140
|
|
|
141
|
+
def primary_key_for(entity_name)
|
|
142
|
+
metadata.xpath("//EntityType[@Name='#{entity_name}']/Key/PropertyRef").first.attributes['Name'].value
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def properties_for(entity_name)
|
|
146
|
+
type_definition = metadata.xpath("//EntityType[@Name='#{entity_name}']").first
|
|
147
|
+
raise ArgumentError, "Unknown EntityType: #{entity_name}" if type_definition.nil?
|
|
148
|
+
properties_to_return = {}
|
|
149
|
+
type_definition.xpath('./Property').each do |property_xml|
|
|
150
|
+
property_name = property_xml.attributes['Name'].value
|
|
151
|
+
value_type = property_xml.attributes['Type'].value
|
|
152
|
+
property_options = {}
|
|
153
|
+
property_options[:allows_nil] = false if property_xml.attributes['Nullable'] == 'false'
|
|
154
|
+
klass_name = value_type.gsub(/^Edm\./, '')
|
|
155
|
+
properties_to_return[property_name] = "OData::Properties::#{klass_name}".constantize.new(property_name, nil, property_options)
|
|
156
|
+
end
|
|
157
|
+
properties_to_return
|
|
158
|
+
end
|
|
159
|
+
|
|
133
160
|
private
|
|
134
161
|
|
|
135
162
|
def default_options
|
|
@@ -151,41 +178,5 @@ module OData
|
|
|
151
178
|
::Nokogiri::XML(response.body).remove_namespaces!
|
|
152
179
|
}.call
|
|
153
180
|
end
|
|
154
|
-
|
|
155
|
-
def build_request_url(model, criteria)
|
|
156
|
-
request_url = "#{service_url}/#{model.odata_name}"
|
|
157
|
-
request_url += "(#{criteria[:key]})" if criteria[:key]
|
|
158
|
-
request_url
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
def parse_model_from_feed(model, entry)
|
|
162
|
-
attributes = {}
|
|
163
|
-
|
|
164
|
-
%w{title summary}.each do |attribute_name|
|
|
165
|
-
attributes[attribute_name.to_sym] = {
|
|
166
|
-
value: entry.xpath("//#{attribute_name}").first.content,
|
|
167
|
-
type: entry.xpath("//#{attribute_name}").first.attributes['type'].value
|
|
168
|
-
}
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
entry.xpath('//content/properties/*').each do |property|
|
|
172
|
-
if property.attributes['null']
|
|
173
|
-
if property.attributes['null'].value == 'true'
|
|
174
|
-
property_type = nil
|
|
175
|
-
else
|
|
176
|
-
property_type = property.attributes['type'].value
|
|
177
|
-
end
|
|
178
|
-
else
|
|
179
|
-
property_type = property.attributes['type'].value
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
attributes[property.name.underscore.to_sym] = {
|
|
183
|
-
value: property.content,
|
|
184
|
-
type: property_type
|
|
185
|
-
}
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
model.load_from_feed(attributes)
|
|
189
|
-
end
|
|
190
181
|
end
|
|
191
182
|
end
|
data/lib/odata/version.rb
CHANGED
data/odata.gemspec
CHANGED
|
@@ -24,6 +24,7 @@ Gem::Specification.new do |spec|
|
|
|
24
24
|
spec.add_development_dependency 'codeclimate-test-reporter'
|
|
25
25
|
spec.add_development_dependency 'rspec', '~> 3.0.0'
|
|
26
26
|
spec.add_development_dependency 'webmock', '~> 1.18.0'
|
|
27
|
+
spec.add_development_dependency 'timecop', '~> 0.7.1'
|
|
27
28
|
|
|
28
29
|
spec.add_dependency 'backports', '~> 3.6.0'
|
|
29
30
|
spec.add_dependency 'nokogiri', '~> 1.6.2'
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<feed xml:base="http://services.odata.org/OData/OData.svc/" xmlns="http://www.w3.org/2005/Atom"
|
|
3
|
+
xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
|
|
4
|
+
xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
|
|
5
|
+
xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml">
|
|
6
|
+
<id>http://services.odata.org/OData/OData.svc/Products</id>
|
|
7
|
+
<title type="text">Products</title>
|
|
8
|
+
<updated>2014-07-07T20:01:27Z</updated>
|
|
9
|
+
<link rel="self" title="Products" href="Products"/>
|
|
10
|
+
<entry>
|
|
11
|
+
<id>http://services.odata.org/OData/OData.svc/Products(0)</id>
|
|
12
|
+
<category term="ODataDemo.Product" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"/>
|
|
13
|
+
<link rel="edit" title="Product" href="Products(0)"/>
|
|
14
|
+
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Categories"
|
|
15
|
+
type="application/atom+xml;type=feed" title="Categories" href="Products(0)/Categories"/>
|
|
16
|
+
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Supplier"
|
|
17
|
+
type="application/atom+xml;type=entry" title="Supplier" href="Products(0)/Supplier"/>
|
|
18
|
+
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ProductDetail"
|
|
19
|
+
type="application/atom+xml;type=entry" title="ProductDetail" href="Products(0)/ProductDetail"/>
|
|
20
|
+
<title type="text">Bread</title>
|
|
21
|
+
<summary type="text">Whole grain bread</summary>
|
|
22
|
+
<updated>2014-07-07T20:01:27Z</updated>
|
|
23
|
+
<author>
|
|
24
|
+
<name/>
|
|
25
|
+
</author>
|
|
26
|
+
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/relatedlinks/Categories" type="application/xml"
|
|
27
|
+
title="Categories" href="Products(0)/$links/Categories"/>
|
|
28
|
+
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/relatedlinks/Supplier" type="application/xml"
|
|
29
|
+
title="Supplier" href="Products(0)/$links/Supplier"/>
|
|
30
|
+
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/relatedlinks/ProductDetail" type="application/xml"
|
|
31
|
+
title="ProductDetail" href="Products(0)/$links/ProductDetail"/>
|
|
32
|
+
<content type="application/xml">
|
|
33
|
+
<m:properties>
|
|
34
|
+
<d:ID m:type="Edm.Int32">0</d:ID>
|
|
35
|
+
<d:ReleaseDate m:type="Edm.DateTime">1992-01-01T00:00:00</d:ReleaseDate>
|
|
36
|
+
<d:DiscontinuedDate m:null="true"/>
|
|
37
|
+
<d:Rating m:type="Edm.Int16">4</d:Rating>
|
|
38
|
+
<d:Price m:type="Edm.Double">2.5</d:Price>
|
|
39
|
+
</m:properties>
|
|
40
|
+
</content>
|
|
41
|
+
</entry>
|
|
42
|
+
</feed>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<entry xml:base="http://services.odata.org/OData/OData.svc/"
|
|
3
|
+
xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
|
|
4
|
+
xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
|
|
5
|
+
xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml">
|
|
6
|
+
<id>http://services.odata.org/OData/OData.svc/Products(9999)</id>
|
|
7
|
+
<category term="ODataDemo.Product" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"/>
|
|
8
|
+
<link rel="edit" title="Product" href="Products(9999)"/>
|
|
9
|
+
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Categories" type="application/atom+xml;type=feed" title="Categories" href="Products(9999)/Categories"/>
|
|
10
|
+
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Supplier" type="application/atom+xml;type=entry" title="Supplier" href="Products(9999)/Supplier"/>
|
|
11
|
+
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ProductDetail" type="application/atom+xml;type=entry" title="ProductDetail" href="Products(9999)/ProductDetail"/>
|
|
12
|
+
<title type="text">Widget</title>
|
|
13
|
+
<summary type="text">A simple widget</summary>
|
|
14
|
+
<updated>2014-07-07T18:47:05Z</updated>
|
|
15
|
+
<author>
|
|
16
|
+
<name/>
|
|
17
|
+
</author>
|
|
18
|
+
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/relatedlinks/Categories" type="application/xml" title="Categories" href="Products(9999)/$links/Categories"/>
|
|
19
|
+
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/relatedlinks/Supplier" type="application/xml" title="Supplier" href="Products(9999)/$links/Supplier"/>
|
|
20
|
+
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/relatedlinks/ProductDetail" type="application/xml" title="ProductDetail" href="Products(9999)/$links/ProductDetail"/>
|
|
21
|
+
<m:action
|
|
22
|
+
metadata="http://services.odata.org/OData/OData.svc/$metadata#DemoService.Discount"
|
|
23
|
+
title="Discount"
|
|
24
|
+
target="http://services.odata.org/OData/OData.svc/Products(9999)/Discount"/>
|
|
25
|
+
<content type="application/xml">
|
|
26
|
+
<m:properties>
|
|
27
|
+
<d:ID m:type="Edm.Int32">9999</d:ID>
|
|
28
|
+
<d:ReleaseDate m:type="Edm.DateTime">2014-07-07T12:44:13</d:ReleaseDate>
|
|
29
|
+
<d:DiscontinuedDate m:null="true"/>
|
|
30
|
+
<d:Rating m:type="Edm.Int16">4</d:Rating>
|
|
31
|
+
<d:Price m:type="Edm.Double">3.5</d:Price>
|
|
32
|
+
</m:properties>
|
|
33
|
+
</content>
|
|
34
|
+
</entry>
|
|
@@ -11,8 +11,7 @@ describe OData::EntitySet do
|
|
|
11
11
|
OData::Service.open('http://services.odata.org/OData/OData.svc')
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
it { expect(subject).to respond_to(:name, :type, :container, :namespace) }
|
|
14
|
+
it { expect(subject).to respond_to(:name, :type, :container, :namespace, :new_entity) }
|
|
16
15
|
|
|
17
16
|
it { expect(subject.name).to eq('Products') }
|
|
18
17
|
it { expect(subject.container).to eq('DemoService') }
|
|
@@ -37,4 +36,65 @@ describe OData::EntitySet do
|
|
|
37
36
|
it { expect(subject).to respond_to(:count) }
|
|
38
37
|
it { expect(subject.count).to eq(11) }
|
|
39
38
|
end
|
|
39
|
+
|
|
40
|
+
describe '#new_entity' do
|
|
41
|
+
let(:new_entity) { subject.new_entity(properties) }
|
|
42
|
+
let(:release_date) { DateTime.new(2014,7,5) }
|
|
43
|
+
let(:properties) { {
|
|
44
|
+
Name: 'Widget',
|
|
45
|
+
Description: 'Just a simple widget',
|
|
46
|
+
ReleaseDate: release_date,
|
|
47
|
+
DiscontinuedDate: nil,
|
|
48
|
+
Rating: 4,
|
|
49
|
+
Price: 3.5
|
|
50
|
+
} }
|
|
51
|
+
|
|
52
|
+
it { expect(new_entity['ID']).to be_nil }
|
|
53
|
+
it { expect(new_entity['Name']).to eq('Widget') }
|
|
54
|
+
it { expect(new_entity['Description']).to eq('Just a simple widget') }
|
|
55
|
+
it { expect(new_entity['ReleaseDate']).to eq(release_date) }
|
|
56
|
+
it { expect(new_entity['DiscontinuedDate']).to be_nil }
|
|
57
|
+
it { expect(new_entity['Rating']).to eq(4) }
|
|
58
|
+
it { expect(new_entity['Price']).to eq(3.5) }
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
describe '#<<' do
|
|
62
|
+
let(:new_entity) { subject.new_entity(properties) }
|
|
63
|
+
let(:bad_entity) { subject.new_entity }
|
|
64
|
+
let(:existing_entity) { subject.first }
|
|
65
|
+
let(:properties) { {
|
|
66
|
+
Name: 'Widget',
|
|
67
|
+
Description: 'Just a simple widget',
|
|
68
|
+
ReleaseDate: DateTime.now.new_offset(0),
|
|
69
|
+
DiscontinuedDate: nil,
|
|
70
|
+
Rating: 4,
|
|
71
|
+
Price: 3.5
|
|
72
|
+
} }
|
|
73
|
+
|
|
74
|
+
it { expect(subject).to respond_to(:<<) }
|
|
75
|
+
|
|
76
|
+
it 'with an existing entity' do
|
|
77
|
+
WebMock.stub_request(:post, 'http://services.odata.org/OData/OData.svc/Products(0)').
|
|
78
|
+
to_return(status: 200, body: File.open('spec/fixtures/sample_service/product_0.xml'))
|
|
79
|
+
|
|
80
|
+
expect {subject << existing_entity}.to_not raise_error
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it 'with a new entity' do
|
|
84
|
+
WebMock.stub_request(:post, 'http://services.odata.org/OData/OData.svc/Products').
|
|
85
|
+
to_return(status: 201, body: File.open('spec/fixtures/sample_service/product_9999.xml'))
|
|
86
|
+
|
|
87
|
+
expect(new_entity['ID']).to be_nil
|
|
88
|
+
expect {subject << new_entity}.to_not raise_error
|
|
89
|
+
expect(new_entity['ID']).to_not be_nil
|
|
90
|
+
expect(new_entity['ID']).to eq(9999)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it 'with a bad entity' do
|
|
94
|
+
WebMock.stub_request(:post, 'http://services.odata.org/OData/OData.svc/Products').
|
|
95
|
+
to_return(status: 400, body: nil)
|
|
96
|
+
|
|
97
|
+
expect {subject << bad_entity}.to raise_error(StandardError, 'Something went wrong committing your entity')
|
|
98
|
+
end
|
|
99
|
+
end
|
|
40
100
|
end
|
data/spec/odata/entity_spec.rb
CHANGED
|
@@ -39,5 +39,8 @@ describe OData::Entity do
|
|
|
39
39
|
it { expect(subject['DiscontinuedDate']).to be_nil }
|
|
40
40
|
it { expect(subject['Rating']).to eq(4) }
|
|
41
41
|
it { expect(subject['Price']).to eq(2.5) }
|
|
42
|
+
|
|
43
|
+
it { expect {subject['NonExistant']}.to raise_error(ArgumentError) }
|
|
44
|
+
it { expect {subject['NonExistant'] = 5}.to raise_error(ArgumentError) }
|
|
42
45
|
end
|
|
43
46
|
end
|
data/spec/odata/service_spec.rb
CHANGED
|
@@ -59,27 +59,6 @@ describe OData::Service do
|
|
|
59
59
|
it { expect(subject.namespace).to eq('ODataDemo') }
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
-
describe '#get' do
|
|
63
|
-
describe 'a set of entities' do
|
|
64
|
-
it { expect(subject.get(::Examples::Product).size).to eq(11) }
|
|
65
|
-
it { expect(subject.get(::Examples::Product).first).to be_instance_of(::Examples::Product) }
|
|
66
|
-
it { expect(subject.get(::Examples::Product).shuffle.first).to be_instance_of(::Examples::Product) }
|
|
67
|
-
it { expect(subject.get(::Examples::Product).last).to be_instance_of(::Examples::Product) }
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
describe 'a specific entity by key' do
|
|
71
|
-
it { expect(subject.get(::Examples::Product, {key: 0}).size).to eq(1) }
|
|
72
|
-
it { expect(subject.get(::Examples::Product, {key: 0}).first).to be_instance_of(::Examples::Product) }
|
|
73
|
-
it { expect(subject.get(::Examples::Product, {key: 0}).first.id).to eq(0) }
|
|
74
|
-
it { expect(subject.get(::Examples::Product, {key: 0}).first.name).to eq('Bread') }
|
|
75
|
-
it { expect(subject.get(::Examples::Product, {key: 0}).first.description).to eq('Whole grain bread') }
|
|
76
|
-
it { expect(subject.get(::Examples::Product, {key: 0}).first.release_date).to eq(DateTime.parse('1992-01-01T00:00:00')) }
|
|
77
|
-
it { expect(subject.get(::Examples::Product, {key: 0}).first.discontinued_date).to eq(nil) }
|
|
78
|
-
it { expect(subject.get(::Examples::Product, {key: 0}).first.rating).to eq(4) }
|
|
79
|
-
it { expect(subject.get(::Examples::Product, {key: 0}).first.price).to eq(2.5) }
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
|
|
83
62
|
describe '#[]' do
|
|
84
63
|
it { expect(subject['Products']).to be_a(OData::EntitySet) }
|
|
85
64
|
it { expect {subject['Nonexistant']}.to raise_error(ArgumentError) }
|
data/spec/spec_helper.rb
CHANGED
|
@@ -17,6 +17,8 @@ else
|
|
|
17
17
|
WebMock.disable_net_connect!(allow_localhost: true, allow: 'codeclimate.com')
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
+
require 'timecop'
|
|
21
|
+
|
|
20
22
|
RSpec.configure do |config|
|
|
21
23
|
if config.files_to_run.one?
|
|
22
24
|
config.default_formatter = 'doc'
|
|
@@ -52,6 +54,9 @@ RSpec.configure do |config|
|
|
|
52
54
|
WebMock.stub_request(:get, 'http://services.odata.org/OData/OData.svc/Products?$inlinecount=allpages&$skip=10&$top=5').
|
|
53
55
|
to_return(status: 200, body: File.open('spec/fixtures/sample_service/products_skip10_top5.xml'))
|
|
54
56
|
|
|
57
|
+
WebMock.stub_request(:get, 'http://services.odata.org/OData/OData.svc/Products?$skip=0&$top=1').
|
|
58
|
+
to_return(status: 200, body: File.open('spec/fixtures/sample_service/first_product.xml'))
|
|
59
|
+
|
|
55
60
|
WebMock.stub_request(:get, 'http://services.odata.org/OData/OData.svc/Products/$count').
|
|
56
61
|
to_return(status: 200, :body => '11')
|
|
57
62
|
|
|
@@ -64,5 +69,6 @@ RSpec.configure do |config|
|
|
|
64
69
|
# We're calling this as a private method because there should not be any
|
|
65
70
|
# reasons to have to flush the service registry except in testing.
|
|
66
71
|
OData::ServiceRegistry.instance.send(:flush)
|
|
72
|
+
WebMock.reset!
|
|
67
73
|
end
|
|
68
74
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: odata
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0
|
|
4
|
+
version: 0.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- James Thompson
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2014-07-
|
|
11
|
+
date: 2014-07-07 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -94,6 +94,20 @@ dependencies:
|
|
|
94
94
|
- - "~>"
|
|
95
95
|
- !ruby/object:Gem::Version
|
|
96
96
|
version: 1.18.0
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: timecop
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - "~>"
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: 0.7.1
|
|
104
|
+
type: :development
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - "~>"
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: 0.7.1
|
|
97
111
|
- !ruby/object:Gem::Dependency
|
|
98
112
|
name: backports
|
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -161,6 +175,7 @@ files:
|
|
|
161
175
|
- ".rspec"
|
|
162
176
|
- ".ruby-version"
|
|
163
177
|
- ".travis.yml"
|
|
178
|
+
- CHANGELOG.md
|
|
164
179
|
- Gemfile
|
|
165
180
|
- LICENSE.txt
|
|
166
181
|
- README.md
|
|
@@ -168,7 +183,6 @@ files:
|
|
|
168
183
|
- lib/odata.rb
|
|
169
184
|
- lib/odata/entity.rb
|
|
170
185
|
- lib/odata/entity_set.rb
|
|
171
|
-
- lib/odata/model.rb
|
|
172
186
|
- lib/odata/properties.rb
|
|
173
187
|
- lib/odata/properties/binary.rb
|
|
174
188
|
- lib/odata/properties/boolean.rb
|
|
@@ -187,16 +201,16 @@ files:
|
|
|
187
201
|
- lib/odata/service_registry.rb
|
|
188
202
|
- lib/odata/version.rb
|
|
189
203
|
- odata.gemspec
|
|
190
|
-
- spec/
|
|
204
|
+
- spec/fixtures/sample_service/first_product.xml
|
|
191
205
|
- spec/fixtures/sample_service/metadata.xml
|
|
192
206
|
- spec/fixtures/sample_service/product_0.xml
|
|
207
|
+
- spec/fixtures/sample_service/product_9999.xml
|
|
193
208
|
- spec/fixtures/sample_service/products.xml
|
|
194
209
|
- spec/fixtures/sample_service/products_skip0_top5.xml
|
|
195
210
|
- spec/fixtures/sample_service/products_skip10_top5.xml
|
|
196
211
|
- spec/fixtures/sample_service/products_skip5_top5.xml
|
|
197
212
|
- spec/odata/entity_set_spec.rb
|
|
198
213
|
- spec/odata/entity_spec.rb
|
|
199
|
-
- spec/odata/model_spec.rb
|
|
200
214
|
- spec/odata/properties/binary_spec.rb
|
|
201
215
|
- spec/odata/properties/boolean_spec.rb
|
|
202
216
|
- spec/odata/properties/date_time_offset_spec.rb
|
|
@@ -236,16 +250,16 @@ signing_key:
|
|
|
236
250
|
specification_version: 4
|
|
237
251
|
summary: Simple OData library
|
|
238
252
|
test_files:
|
|
239
|
-
- spec/
|
|
253
|
+
- spec/fixtures/sample_service/first_product.xml
|
|
240
254
|
- spec/fixtures/sample_service/metadata.xml
|
|
241
255
|
- spec/fixtures/sample_service/product_0.xml
|
|
256
|
+
- spec/fixtures/sample_service/product_9999.xml
|
|
242
257
|
- spec/fixtures/sample_service/products.xml
|
|
243
258
|
- spec/fixtures/sample_service/products_skip0_top5.xml
|
|
244
259
|
- spec/fixtures/sample_service/products_skip10_top5.xml
|
|
245
260
|
- spec/fixtures/sample_service/products_skip5_top5.xml
|
|
246
261
|
- spec/odata/entity_set_spec.rb
|
|
247
262
|
- spec/odata/entity_spec.rb
|
|
248
|
-
- spec/odata/model_spec.rb
|
|
249
263
|
- spec/odata/properties/binary_spec.rb
|
|
250
264
|
- spec/odata/properties/boolean_spec.rb
|
|
251
265
|
- spec/odata/properties/date_time_offset_spec.rb
|
data/lib/odata/model.rb
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
require 'odata/property'
|
|
2
|
-
require 'odata/properties'
|
|
3
|
-
|
|
4
|
-
module OData
|
|
5
|
-
# Provides a convenient way to represent OData entities as Ruby objects.
|
|
6
|
-
# Instances that include this module gain the ability to define how to map
|
|
7
|
-
# OData properties to attributes as well as the ability to query and persist
|
|
8
|
-
# data to the underlying OData service.
|
|
9
|
-
#
|
|
10
|
-
# If the module detects the presence of Rails, along with ActiveModel::Model
|
|
11
|
-
# it will automatically mixin support ActiveModel::Model to provide better
|
|
12
|
-
# integration with Rails apps.
|
|
13
|
-
module Model
|
|
14
|
-
extend ::ActiveSupport::Concern
|
|
15
|
-
include ::ActiveModel::Model if defined?(::Rails) && defined?(::ActiveModel::Model)
|
|
16
|
-
|
|
17
|
-
included do
|
|
18
|
-
cattr_accessor :registered_properties
|
|
19
|
-
cattr_accessor :primary_key
|
|
20
|
-
|
|
21
|
-
self.class_eval <<-EOS
|
|
22
|
-
@@registered_properties = {}
|
|
23
|
-
@@primary_key = nil
|
|
24
|
-
EOS
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
# Converts supplied value based on its type
|
|
28
|
-
#
|
|
29
|
-
# @param value [*] usually a string representation of the value
|
|
30
|
-
# @param type [String] OData type name as string
|
|
31
|
-
# @return [*]
|
|
32
|
-
def convert_value_for_type(value, type)
|
|
33
|
-
return nil if value.nil? || type.nil?
|
|
34
|
-
if type =~ /Int(16|32|64)$/
|
|
35
|
-
value.to_i
|
|
36
|
-
elsif type =~ /Boolean$/
|
|
37
|
-
(value == 'true' || value == '1')
|
|
38
|
-
elsif type =~ /(Decimal|Double|Single)$/
|
|
39
|
-
value.to_f
|
|
40
|
-
elsif type =~ /DateTime$/
|
|
41
|
-
DateTime.parse(value)
|
|
42
|
-
else
|
|
43
|
-
value.to_s
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
module ClassMethods
|
|
48
|
-
# Returns the class' name
|
|
49
|
-
def model_name
|
|
50
|
-
self.to_s.demodulize
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
# Pluralizes #model_name for OData requests
|
|
54
|
-
def odata_name
|
|
55
|
-
model_name.pluralize
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
# Instantiates an OData::Model instance from a hash of attributes and
|
|
59
|
-
# their details.
|
|
60
|
-
#
|
|
61
|
-
# @param feed_hash [Hash] attribute names as keys, and details as values
|
|
62
|
-
# @return [OData::Model]
|
|
63
|
-
def load_from_feed(feed_hash)
|
|
64
|
-
loaded_instance = self.new
|
|
65
|
-
feed_hash.each do |attribute_name, details|
|
|
66
|
-
loaded_instance.instance_eval do
|
|
67
|
-
@properties ||= {}
|
|
68
|
-
@properties[attribute_name] = convert_value_for_type(details[:value], details[:type])
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
loaded_instance
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
# Define a property and it's options
|
|
75
|
-
#
|
|
76
|
-
# @param name [to_s] the literal property name expected by the OData service
|
|
77
|
-
# @param options [Hash] options for setting up the property
|
|
78
|
-
def property(name, options = {})
|
|
79
|
-
register_property(name.to_s.underscore, {literal_name: name}.merge(options))
|
|
80
|
-
create_accessors(name.to_s.underscore, options)
|
|
81
|
-
register_primary_key(name.to_s.underscore) if options[:primary_key]
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
private
|
|
85
|
-
|
|
86
|
-
def register_property(name, options)
|
|
87
|
-
new_registered_properties = registered_properties
|
|
88
|
-
new_registered_properties[name.to_sym] = options
|
|
89
|
-
registered_properties = new_registered_properties
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def create_accessors(name, options)
|
|
93
|
-
self.class_eval do
|
|
94
|
-
if options[:entity_title]
|
|
95
|
-
define_method(name) { @properties[:title] || nil }
|
|
96
|
-
define_method("#{name}=") {|value| @properties[:title] = value}
|
|
97
|
-
elsif options[:entity_summary]
|
|
98
|
-
define_method(name) { @properties[:summary] || nil }
|
|
99
|
-
define_method("#{name}=") {|value| @properties[:summary] = value}
|
|
100
|
-
else
|
|
101
|
-
define_method(name) { @properties[name.to_sym] || nil }
|
|
102
|
-
define_method("#{name}=") {|value| @properties[name.to_sym] = value}
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def register_primary_key(name)
|
|
108
|
-
if primary_key.nil?
|
|
109
|
-
self.class_eval <<-EOS
|
|
110
|
-
@@primary_key = :#{name}
|
|
111
|
-
EOS
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
end
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
module Examples
|
|
2
|
-
class Product
|
|
3
|
-
include OData::Model
|
|
4
|
-
|
|
5
|
-
property 'ID', primary_key: true
|
|
6
|
-
property 'Name', entity_title: true
|
|
7
|
-
property 'Description', entity_summary: true
|
|
8
|
-
property 'ReleaseDate'
|
|
9
|
-
property 'DiscontinuedDate'
|
|
10
|
-
property 'Rating'
|
|
11
|
-
property 'Price'
|
|
12
|
-
end
|
|
13
|
-
end
|
data/spec/odata/model_spec.rb
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'examples/product_model'
|
|
3
|
-
|
|
4
|
-
describe OData::Model do
|
|
5
|
-
describe 'class methods' do
|
|
6
|
-
it { expect(::Examples::Product).to respond_to(:model_name) }
|
|
7
|
-
it { expect(::Examples::Product.model_name).to eq('Product') }
|
|
8
|
-
it { expect(::Examples::Product.odata_name).to eq('Products') }
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
describe 'defining properties' do
|
|
12
|
-
let(:subject) { ::Examples::Product.new }
|
|
13
|
-
|
|
14
|
-
it { expect(subject).to respond_to(:id) }
|
|
15
|
-
it { expect(subject).to respond_to(:name) }
|
|
16
|
-
it { expect(subject).to respond_to(:description) }
|
|
17
|
-
it { expect(subject).to respond_to(:release_date) }
|
|
18
|
-
it { expect(subject).to respond_to(:discontinued_date) }
|
|
19
|
-
it { expect(subject).to respond_to(:rating) }
|
|
20
|
-
it { expect(subject).to respond_to(:price) }
|
|
21
|
-
|
|
22
|
-
it { expect(::Examples::Product).to respond_to(:primary_key) }
|
|
23
|
-
it { expect(::Examples::Product.primary_key).to eq(:id)}
|
|
24
|
-
end
|
|
25
|
-
end
|