microsoft_graph 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +11 -11
  3. data/.rspec +2 -2
  4. data/.travis.yml +4 -4
  5. data/Gemfile +4 -4
  6. data/LICENSE +10 -10
  7. data/README.md +99 -98
  8. data/Rakefile +7 -7
  9. data/data/metadata_v1.0.xml +1686 -1686
  10. data/integration_spec/integration_spec_helper.rb +18 -18
  11. data/integration_spec/live_spec.rb +180 -180
  12. data/lib/microsoft_graph.rb +35 -35
  13. data/lib/microsoft_graph/base.rb +110 -110
  14. data/lib/microsoft_graph/base_entity.rb +152 -152
  15. data/lib/microsoft_graph/cached_metadata_directory.rb +3 -3
  16. data/lib/microsoft_graph/class_builder.rb +217 -217
  17. data/lib/microsoft_graph/collection.rb +95 -95
  18. data/lib/microsoft_graph/collection_association.rb +232 -232
  19. data/lib/microsoft_graph/errors.rb +6 -6
  20. data/lib/microsoft_graph/version.rb +3 -3
  21. data/lib/odata.rb +49 -49
  22. data/lib/odata/entity_set.rb +20 -20
  23. data/lib/odata/errors.rb +18 -18
  24. data/lib/odata/navigation_property.rb +30 -30
  25. data/lib/odata/operation.rb +17 -17
  26. data/lib/odata/property.rb +38 -38
  27. data/lib/odata/request.rb +49 -49
  28. data/lib/odata/service.rb +279 -279
  29. data/lib/odata/singleton.rb +20 -20
  30. data/lib/odata/type.rb +25 -25
  31. data/lib/odata/types/collection_type.rb +30 -30
  32. data/lib/odata/types/complex_type.rb +19 -19
  33. data/lib/odata/types/entity_type.rb +33 -33
  34. data/lib/odata/types/enum_type.rb +37 -37
  35. data/lib/odata/types/primitive_type.rb +12 -12
  36. data/lib/odata/types/primitive_types/binary_type.rb +15 -15
  37. data/lib/odata/types/primitive_types/boolean_type.rb +15 -15
  38. data/lib/odata/types/primitive_types/date_time_offset_type.rb +15 -15
  39. data/lib/odata/types/primitive_types/date_type.rb +23 -23
  40. data/lib/odata/types/primitive_types/double_type.rb +16 -16
  41. data/lib/odata/types/primitive_types/guid_type.rb +24 -24
  42. data/lib/odata/types/primitive_types/int_16_type.rb +19 -19
  43. data/lib/odata/types/primitive_types/int_32_type.rb +15 -15
  44. data/lib/odata/types/primitive_types/int_64_type.rb +15 -15
  45. data/lib/odata/types/primitive_types/stream_type.rb +15 -15
  46. data/lib/odata/types/primitive_types/string_type.rb +15 -15
  47. data/microsoft_graph-0.1.2.gem +0 -0
  48. data/microsoft_graph.gemspec +31 -31
  49. data/tasks/update_metadata.rb +17 -17
  50. metadata +6 -6
  51. data/microsoft_graph-0.1.0.gem +0 -0
@@ -1,279 +1,279 @@
1
- module OData
2
- class Service
3
- attr_reader :base_url
4
- attr_reader :metadata
5
-
6
- def initialize(options = {}, &block)
7
- @auth_callback = options[:auth_callback] || block
8
- @base_url = options[:base_url]
9
- @metadata_file = options[:metadata_file]
10
- @type_name_map = {}
11
- @metadata = fetch_metadata
12
- populate_types_from_metadata
13
- end
14
-
15
- def namespace
16
- schema_defintion = metadata.xpath("//Schema") && metadata.xpath("//Schema").first
17
- schema_defintion["Namespace"] if schema_defintion
18
- end
19
-
20
- def inspect
21
- "#<#{self.class} #{base_url}>"
22
- end
23
-
24
- def get(path, *select_properties)
25
- camel_case_select_properties = select_properties.map do |prop|
26
- OData.convert_to_camel_case(prop)
27
- end
28
-
29
- if ! camel_case_select_properties.empty?
30
- encoded_select_properties = URI.encode_www_form(
31
- '$select' => camel_case_select_properties.join(',')
32
- )
33
- path = "#{path}?#{encoded_select_properties}"
34
- end
35
-
36
- response = request(
37
- method: :get,
38
- uri: "#{base_url}#{path}"
39
- )
40
- {type: get_type_for_odata_response(response), attributes: response}
41
- end
42
-
43
- def delete(path)
44
- request(
45
- method: :delete,
46
- uri: "#{base_url}#{path}"
47
- )
48
- end
49
-
50
- def post(path, data)
51
- request(
52
- method: :post,
53
- uri: "#{base_url}#{path}",
54
- data: data
55
- )
56
- end
57
-
58
- def patch(path, data)
59
- request(
60
- method: :patch,
61
- uri: "#{base_url}#{path}",
62
- data: data
63
- )
64
- end
65
-
66
- def request(options = {})
67
- req = Request.new(options[:method], options[:uri], options[:data])
68
- @auth_callback.call(req) if @auth_callback
69
- req.perform
70
- end
71
-
72
- def complex_types
73
- @complex_types ||= metadata.xpath("//ComplexType").map do |complex_type|
74
- @type_name_map["#{namespace}.#{complex_type["Name"]}"] = ComplexType.new(
75
- name: "#{namespace}.#{complex_type["Name"]}",
76
- base_type: complex_type["BaseType"],
77
- service: self,
78
- )
79
- end
80
- end
81
-
82
- def entity_types
83
- @entity_types ||= metadata.xpath("//EntityType").map do |entity|
84
- options = {
85
- name: "#{namespace}.#{entity["Name"]}",
86
- abstract: entity["Abstract"] == "true",
87
- base_type: entity["BaseType"],
88
- open_type: entity["OpenType"] == "true",
89
- has_stream: entity["HasStream"] == "true",
90
- service: self,
91
- }
92
- @type_name_map["#{namespace}.#{entity["Name"]}"] = EntityType.new(options)
93
- end
94
- end
95
-
96
- def enum_types
97
- @enum_types ||= metadata.xpath("//EnumType").map do |type|
98
- members = type.xpath("./Member").map do |m, i|
99
- value = m['Value'] && m['Value'].to_i || i
100
- {
101
- name: m["Name"],
102
- value: value,
103
- }
104
- end
105
- @type_name_map["#{namespace}.#{type["Name"]}"] = EnumType.new({name: "#{namespace}.#{type["Name"]}", members: members})
106
- end
107
- end
108
-
109
- def actions
110
- metadata.xpath("//Action").map do |action|
111
- build_operation(action)
112
- end
113
- end
114
-
115
- def functions
116
- metadata.xpath("//Function").map do |function|
117
- build_operation(function)
118
- end
119
- end
120
-
121
- def populate_primitive_types
122
- @type_name_map.merge!(
123
- "Edm.Binary" => OData::BinaryType.new,
124
- "Edm.Date" => OData::DateType.new,
125
- "Edm.Double" => OData::DoubleType.new,
126
- "Edm.Guid" => OData::GuidType.new,
127
- "Edm.Int16" => OData::Int16Type.new,
128
- "Edm.Int32" => OData::Int32Type.new,
129
- "Edm.Int64" => OData::Int64Type.new,
130
- "Edm.Stream" => OData::StreamType.new,
131
- "Edm.String" => OData::StringType.new,
132
- "Edm.Boolean" => OData::BooleanType.new,
133
- "Edm.DateTimeOffset" => OData::DateTimeOffsetType.new
134
- )
135
- end
136
-
137
- def singletons
138
- metadata.xpath("//Singleton").map do |singleton|
139
- Singleton.new(
140
- name: singleton["Name"],
141
- type: singleton["Type"],
142
- service: self
143
- )
144
- end
145
- end
146
-
147
- def entity_sets
148
- @entity_sets ||= metadata.xpath("//EntitySet").map do |entity_set|
149
- EntitySet.new(
150
- name: entity_set["Name"],
151
- member_type: entity_set["EntityType"],
152
- service: self
153
- )
154
- end
155
- end
156
-
157
- def get_type_for_odata_response(parsed_response)
158
- if odata_type_string = parsed_response["@odata.type"]
159
- get_type_by_name(type_name_from_odata_type_field(odata_type_string))
160
- elsif context = parsed_response["@odata.context"]
161
- singular, segments = segments_from_odata_context_field(context)
162
- first_entity_type = get_type_by_name("Collection(#{entity_set_by_name(segments.shift).member_type})")
163
- entity_type = segments.reduce(first_entity_type) do |last_entity_type, segment|
164
- last_entity_type.member_type.navigation_property_by_name(segment).type
165
- end
166
- singular && entity_type.respond_to?(:member_type) ? entity_type.member_type : entity_type
167
- end
168
- end
169
-
170
- def get_type_by_name(type_name)
171
- @type_name_map[type_name] || build_collection(type_name)
172
- end
173
-
174
- def entity_set_by_name(name)
175
- entity_sets.find { |entity_set| entity_set.name == name }
176
- end
177
-
178
- def properties_for_type(type_name)
179
- raw_type_name = remove_namespace(type_name)
180
- type_definition = metadata.xpath("//EntityType[@Name='#{raw_type_name}']|//ComplexType[@Name='#{raw_type_name}']")
181
- type_definition.xpath("./Property").map do |property|
182
- options = {
183
- name: property["Name"],
184
- nullable: property["Nullable"] != "false",
185
- type: get_type_by_name(property["Type"]),
186
- }
187
- OData::Property.new(options)
188
- end
189
- end
190
-
191
- def navigation_properties_for_type(type_name)
192
- raw_type_name = remove_namespace(type_name)
193
- type_definition = metadata.xpath("//EntityType[@Name='#{raw_type_name}']|//ComplexType[@Name='#{raw_type_name}']")
194
- type_definition.xpath("./NavigationProperty").map do |property|
195
- options = {
196
- name: property["Name"],
197
- nullable: property["Nullable"] != "false",
198
- type: get_type_by_name(property["Type"]),
199
- contains_target: property["ContainsTarget"],
200
- partner: property["Partner"],
201
- }
202
- OData::NavigationProperty.new(options)
203
- end
204
- end
205
-
206
- private
207
-
208
- def type_name_from_odata_type_field(odata_type_field)
209
- odata_type_field.sub("#", '')
210
- end
211
-
212
- def segments_from_odata_context_field(odata_context_field)
213
- segments = odata_context_field.split("$metadata#").last.split("/").map { |s| s.split("(").first }
214
- segments.pop if singular = segments.last == "$entity"
215
- [singular, segments]
216
- end
217
-
218
- def populate_types_from_metadata
219
- enum_types
220
- populate_primitive_types
221
- complex_types
222
- entity_types
223
- end
224
-
225
- def fetch_metadata
226
- response = if @metadata_file
227
- File.read(@metadata_file)
228
- else # From a URL
229
- uri = URI("#{base_url}$metadata?detailed=true")
230
- Net::HTTP
231
- .new(uri.hostname, uri.port)
232
- .tap { |h| h.use_ssl = uri.scheme == "https" }
233
- .get(uri).body
234
- end
235
- ::Nokogiri::XML(response).remove_namespaces!
236
- end
237
-
238
- def build_collection(collection_name)
239
- member_type_name = collection_name.gsub(/Collection\(([^)]+)\)/, "\\1")
240
- CollectionType.new(name: collection_name, member_type: @type_name_map[member_type_name])
241
- end
242
-
243
- def build_operation(operation_xml)
244
- binding_type = if operation_xml["IsBound"] == "true"
245
- type_name = operation_xml.xpath("./Parameter[@Name='bindingParameter']|./Parameter[@Name='bindingparameter']").first["Type"]
246
- get_type_by_name(type_name)
247
- end
248
- entity_set_type = if operation_xml["EntitySetType"]
249
- entity_set_by_name(operation_xml["EntitySetType"])
250
- end
251
- parameters = operation_xml.xpath("./Parameter").inject([]) do |result, parameter|
252
- unless parameter["Name"] == 'bindingParameter'
253
- result.push({
254
- name: parameter["Name"],
255
- type: get_type_by_name(parameter["Type"]),
256
- nullable: parameter["Nullable"],
257
- })
258
- end
259
- result
260
- end
261
- return_type = if return_type_node = operation_xml.xpath("./ReturnType").first
262
- get_type_by_name(return_type_node["Type"])
263
- end
264
-
265
- options = {
266
- name: operation_xml["Name"],
267
- entity_set_type: entity_set_type,
268
- binding_type: binding_type,
269
- parameters: parameters,
270
- return_type: return_type
271
- }
272
- Operation.new(options)
273
- end
274
-
275
- def remove_namespace(name)
276
- name.gsub("#{namespace}.", "")
277
- end
278
- end
279
- end
1
+ module OData
2
+ class Service
3
+ attr_reader :base_url
4
+ attr_reader :metadata
5
+
6
+ def initialize(options = {}, &block)
7
+ @auth_callback = options[:auth_callback] || block
8
+ @base_url = options[:base_url]
9
+ @metadata_file = options[:metadata_file]
10
+ @type_name_map = {}
11
+ @metadata = fetch_metadata
12
+ populate_types_from_metadata
13
+ end
14
+
15
+ def namespace
16
+ schema_defintion = metadata.xpath("//Schema") && metadata.xpath("//Schema").first
17
+ schema_defintion["Namespace"] if schema_defintion
18
+ end
19
+
20
+ def inspect
21
+ "#<#{self.class} #{base_url}>"
22
+ end
23
+
24
+ def get(path, *select_properties)
25
+ camel_case_select_properties = select_properties.map do |prop|
26
+ OData.convert_to_camel_case(prop)
27
+ end
28
+
29
+ if ! camel_case_select_properties.empty?
30
+ encoded_select_properties = URI.encode_www_form(
31
+ '$select' => camel_case_select_properties.join(',')
32
+ )
33
+ path = "#{path}?#{encoded_select_properties}"
34
+ end
35
+
36
+ response = request(
37
+ method: :get,
38
+ uri: "#{base_url}#{path}"
39
+ )
40
+ {type: get_type_for_odata_response(response), attributes: response}
41
+ end
42
+
43
+ def delete(path)
44
+ request(
45
+ method: :delete,
46
+ uri: "#{base_url}#{path}"
47
+ )
48
+ end
49
+
50
+ def post(path, data)
51
+ request(
52
+ method: :post,
53
+ uri: "#{base_url}#{path}",
54
+ data: data
55
+ )
56
+ end
57
+
58
+ def patch(path, data)
59
+ request(
60
+ method: :patch,
61
+ uri: "#{base_url}#{path}",
62
+ data: data
63
+ )
64
+ end
65
+
66
+ def request(options = {})
67
+ req = Request.new(options[:method], options[:uri], options[:data])
68
+ @auth_callback.call(req) if @auth_callback
69
+ req.perform
70
+ end
71
+
72
+ def complex_types
73
+ @complex_types ||= metadata.xpath("//ComplexType").map do |complex_type|
74
+ @type_name_map["#{namespace}.#{complex_type["Name"]}"] = ComplexType.new(
75
+ name: "#{namespace}.#{complex_type["Name"]}",
76
+ base_type: complex_type["BaseType"],
77
+ service: self,
78
+ )
79
+ end
80
+ end
81
+
82
+ def entity_types
83
+ @entity_types ||= metadata.xpath("//EntityType").map do |entity|
84
+ options = {
85
+ name: "#{namespace}.#{entity["Name"]}",
86
+ abstract: entity["Abstract"] == "true",
87
+ base_type: entity["BaseType"],
88
+ open_type: entity["OpenType"] == "true",
89
+ has_stream: entity["HasStream"] == "true",
90
+ service: self,
91
+ }
92
+ @type_name_map["#{namespace}.#{entity["Name"]}"] = EntityType.new(options)
93
+ end
94
+ end
95
+
96
+ def enum_types
97
+ @enum_types ||= metadata.xpath("//EnumType").map do |type|
98
+ members = type.xpath("./Member").map do |m, i|
99
+ value = m['Value'] && m['Value'].to_i || i
100
+ {
101
+ name: m["Name"],
102
+ value: value,
103
+ }
104
+ end
105
+ @type_name_map["#{namespace}.#{type["Name"]}"] = EnumType.new({name: "#{namespace}.#{type["Name"]}", members: members})
106
+ end
107
+ end
108
+
109
+ def actions
110
+ metadata.xpath("//Action").map do |action|
111
+ build_operation(action)
112
+ end
113
+ end
114
+
115
+ def functions
116
+ metadata.xpath("//Function").map do |function|
117
+ build_operation(function)
118
+ end
119
+ end
120
+
121
+ def populate_primitive_types
122
+ @type_name_map.merge!(
123
+ "Edm.Binary" => OData::BinaryType.new,
124
+ "Edm.Date" => OData::DateType.new,
125
+ "Edm.Double" => OData::DoubleType.new,
126
+ "Edm.Guid" => OData::GuidType.new,
127
+ "Edm.Int16" => OData::Int16Type.new,
128
+ "Edm.Int32" => OData::Int32Type.new,
129
+ "Edm.Int64" => OData::Int64Type.new,
130
+ "Edm.Stream" => OData::StreamType.new,
131
+ "Edm.String" => OData::StringType.new,
132
+ "Edm.Boolean" => OData::BooleanType.new,
133
+ "Edm.DateTimeOffset" => OData::DateTimeOffsetType.new
134
+ )
135
+ end
136
+
137
+ def singletons
138
+ metadata.xpath("//Singleton").map do |singleton|
139
+ Singleton.new(
140
+ name: singleton["Name"],
141
+ type: singleton["Type"],
142
+ service: self
143
+ )
144
+ end
145
+ end
146
+
147
+ def entity_sets
148
+ @entity_sets ||= metadata.xpath("//EntitySet").map do |entity_set|
149
+ EntitySet.new(
150
+ name: entity_set["Name"],
151
+ member_type: entity_set["EntityType"],
152
+ service: self
153
+ )
154
+ end
155
+ end
156
+
157
+ def get_type_for_odata_response(parsed_response)
158
+ if odata_type_string = parsed_response["@odata.type"]
159
+ get_type_by_name(type_name_from_odata_type_field(odata_type_string))
160
+ elsif context = parsed_response["@odata.context"]
161
+ singular, segments = segments_from_odata_context_field(context)
162
+ first_entity_type = get_type_by_name("Collection(#{entity_set_by_name(segments.shift).member_type})")
163
+ entity_type = segments.reduce(first_entity_type) do |last_entity_type, segment|
164
+ last_entity_type.member_type.navigation_property_by_name(segment).type
165
+ end
166
+ singular && entity_type.respond_to?(:member_type) ? entity_type.member_type : entity_type
167
+ end
168
+ end
169
+
170
+ def get_type_by_name(type_name)
171
+ @type_name_map[type_name] || build_collection(type_name)
172
+ end
173
+
174
+ def entity_set_by_name(name)
175
+ entity_sets.find { |entity_set| entity_set.name == name }
176
+ end
177
+
178
+ def properties_for_type(type_name)
179
+ raw_type_name = remove_namespace(type_name)
180
+ type_definition = metadata.xpath("//EntityType[@Name='#{raw_type_name}']|//ComplexType[@Name='#{raw_type_name}']")
181
+ type_definition.xpath("./Property").map do |property|
182
+ options = {
183
+ name: property["Name"],
184
+ nullable: property["Nullable"] != "false",
185
+ type: get_type_by_name(property["Type"]),
186
+ }
187
+ OData::Property.new(options)
188
+ end
189
+ end
190
+
191
+ def navigation_properties_for_type(type_name)
192
+ raw_type_name = remove_namespace(type_name)
193
+ type_definition = metadata.xpath("//EntityType[@Name='#{raw_type_name}']|//ComplexType[@Name='#{raw_type_name}']")
194
+ type_definition.xpath("./NavigationProperty").map do |property|
195
+ options = {
196
+ name: property["Name"],
197
+ nullable: property["Nullable"] != "false",
198
+ type: get_type_by_name(property["Type"]),
199
+ contains_target: property["ContainsTarget"],
200
+ partner: property["Partner"],
201
+ }
202
+ OData::NavigationProperty.new(options)
203
+ end
204
+ end
205
+
206
+ private
207
+
208
+ def type_name_from_odata_type_field(odata_type_field)
209
+ odata_type_field.sub("#", '')
210
+ end
211
+
212
+ def segments_from_odata_context_field(odata_context_field)
213
+ segments = odata_context_field.split("$metadata#").last.split("/").map { |s| s.split("(").first }
214
+ segments.pop if singular = segments.last == "$entity"
215
+ [singular, segments]
216
+ end
217
+
218
+ def populate_types_from_metadata
219
+ enum_types
220
+ populate_primitive_types
221
+ complex_types
222
+ entity_types
223
+ end
224
+
225
+ def fetch_metadata
226
+ response = if @metadata_file
227
+ File.read(@metadata_file)
228
+ else # From a URL
229
+ uri = URI("#{base_url}$metadata?detailed=true")
230
+ Net::HTTP
231
+ .new(uri.hostname, uri.port)
232
+ .tap { |h| h.use_ssl = uri.scheme == "https" }
233
+ .get(uri).body
234
+ end
235
+ ::Nokogiri::XML(response).remove_namespaces!
236
+ end
237
+
238
+ def build_collection(collection_name)
239
+ member_type_name = collection_name.gsub(/Collection\(([^)]+)\)/, "\\1")
240
+ CollectionType.new(name: collection_name, member_type: @type_name_map[member_type_name])
241
+ end
242
+
243
+ def build_operation(operation_xml)
244
+ binding_type = if operation_xml["IsBound"] == "true"
245
+ type_name = operation_xml.xpath("./Parameter[@Name='bindingParameter']|./Parameter[@Name='bindingparameter']").first["Type"]
246
+ get_type_by_name(type_name)
247
+ end
248
+ entity_set_type = if operation_xml["EntitySetType"]
249
+ entity_set_by_name(operation_xml["EntitySetType"])
250
+ end
251
+ parameters = operation_xml.xpath("./Parameter").inject([]) do |result, parameter|
252
+ unless parameter["Name"] == 'bindingParameter'
253
+ result.push({
254
+ name: parameter["Name"],
255
+ type: get_type_by_name(parameter["Type"]),
256
+ nullable: parameter["Nullable"],
257
+ })
258
+ end
259
+ result
260
+ end
261
+ return_type = if return_type_node = operation_xml.xpath("./ReturnType").first
262
+ get_type_by_name(return_type_node["Type"])
263
+ end
264
+
265
+ options = {
266
+ name: operation_xml["Name"],
267
+ entity_set_type: entity_set_type,
268
+ binding_type: binding_type,
269
+ parameters: parameters,
270
+ return_type: return_type
271
+ }
272
+ Operation.new(options)
273
+ end
274
+
275
+ def remove_namespace(name)
276
+ name.gsub("#{namespace}.", "")
277
+ end
278
+ end
279
+ end