ruby_odata 0.1.0 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +7 -2
  4. data/.simplecov +10 -0
  5. data/.travis.yml +10 -4
  6. data/.yardopts +6 -0
  7. data/CHANGELOG.md +157 -0
  8. data/Guardfile +14 -0
  9. data/LICENSE +20 -22
  10. data/README.md +289 -0
  11. data/Rakefile +19 -9
  12. data/features/basic_auth.feature +3 -2
  13. data/features/batch_request.feature +7 -6
  14. data/features/cassettes/basic_auth_protected_resource.yml +57 -0
  15. data/features/cassettes/batch_request_additions.yml +69 -0
  16. data/features/cassettes/batch_request_deletes.yml +69 -0
  17. data/features/cassettes/batch_request_updates.yml +69 -0
  18. data/features/cassettes/clean_database_for_testing.yml +46 -0
  19. data/features/cassettes/cucumber_tags/basic_auth.yml +297 -0
  20. data/features/cassettes/cucumber_tags/batch_request.yml +1459 -0
  21. data/features/cassettes/cucumber_tags/complex_types.yml +326 -0
  22. data/features/cassettes/cucumber_tags/error_handling.yml +64 -0
  23. data/features/cassettes/cucumber_tags/query_builder.yml +2025 -0
  24. data/features/cassettes/cucumber_tags/service.yml +234 -0
  25. data/features/cassettes/cucumber_tags/service_manage.yml +937 -0
  26. data/features/cassettes/cucumber_tags/service_methods.yml +647 -0
  27. data/features/cassettes/cucumber_tags/ssl.yml +203 -0
  28. data/features/cassettes/cucumber_tags/type_conversion.yml +337 -0
  29. data/features/cassettes/service_manage_additions.yml +65 -0
  30. data/features/cassettes/service_manage_deletions.yml +58 -0
  31. data/features/cassettes/service_manage_deletions_2.yml +58 -0
  32. data/features/cassettes/unsecured_metadata.yml +89 -0
  33. data/features/complex_types.feature +4 -3
  34. data/features/error_handling.feature +13 -0
  35. data/features/query_builder.feature +30 -9
  36. data/features/service.feature +4 -3
  37. data/features/service_manage.feature +6 -5
  38. data/features/service_methods.feature +3 -2
  39. data/features/ssl.feature +8 -8
  40. data/features/step_definitions/service_steps.rb +32 -74
  41. data/features/support/env.rb +6 -3
  42. data/features/support/hooks.rb +3 -2
  43. data/features/support/pickle.rb +29 -18
  44. data/features/support/vcr.rb +24 -0
  45. data/features/type_conversion.feature +16 -17
  46. data/gemfiles/Gemfile.ruby187 +6 -0
  47. data/lib/ruby_odata.rb +20 -18
  48. data/lib/ruby_odata/association.rb +7 -6
  49. data/lib/ruby_odata/class_builder.rb +31 -14
  50. data/lib/ruby_odata/exceptions.rb +11 -0
  51. data/lib/ruby_odata/helpers.rb +17 -0
  52. data/lib/ruby_odata/operation.rb +5 -6
  53. data/lib/ruby_odata/property_metadata.rb +9 -7
  54. data/lib/ruby_odata/query_builder.rb +127 -63
  55. data/lib/ruby_odata/service.rb +265 -147
  56. data/lib/ruby_odata/version.rb +3 -1
  57. data/ruby_odata.gemspec +22 -13
  58. data/spec/fixtures/error_without_message.xml +5 -0
  59. data/spec/fixtures/int64_ids/edmx_boat_service.xml +19 -0
  60. data/spec/fixtures/int64_ids/edmx_car_service.xml +21 -0
  61. data/spec/fixtures/int64_ids/result_boats.xml +26 -0
  62. data/spec/fixtures/int64_ids/result_cars.xml +28 -0
  63. data/spec/fixtures/ms_system_center/edmx_ms_system_center.xml +1645 -0
  64. data/spec/fixtures/ms_system_center/edmx_ms_system_center_v2.xml +2120 -0
  65. data/spec/fixtures/ms_system_center/hardware_profiles.xml +61 -0
  66. data/spec/fixtures/ms_system_center/virtual_machines.xml +175 -0
  67. data/spec/fixtures/ms_system_center/vm_templates.xml +1193 -0
  68. data/spec/fixtures/nested_expands/edmx_northwind.xml +557 -0
  69. data/spec/fixtures/nested_expands/northwind_products_category_expands.xml +774 -0
  70. data/spec/fixtures/sample_service/result_select_categories_expand.xml +268 -0
  71. data/spec/fixtures/sample_service/result_select_categories_no_property.xml +6 -0
  72. data/spec/fixtures/sample_service/result_select_categories_travsing_no_expand.xml +6 -0
  73. data/spec/fixtures/sample_service/result_select_products_name_price.xml +92 -0
  74. data/spec/property_metadata_spec.rb +10 -10
  75. data/spec/query_builder_spec.rb +153 -14
  76. data/spec/revised_service_spec.rb +111 -6
  77. data/spec/service_spec.rb +389 -85
  78. data/spec/spec_helper.rb +3 -0
  79. data/spec/support/sample_service_matcher.rb +15 -0
  80. data/test/RubyODataService/RubyODataService/App_Data/.gitkeep +0 -0
  81. data/test/blueprints.rb +15 -9
  82. data/test/usage_samples/querying.rb +5 -1
  83. data/test/usage_samples/sample_data.rb +1 -3
  84. metadata +276 -76
  85. data/CHANGELOG.rdoc +0 -88
  86. data/README.rdoc +0 -259
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 13c318e42410f72bfbdb32c56c0286047a8c4ffb
4
+ data.tar.gz: 829b8aaf44049a72fe928006c4c0d949b029afb4
5
+ SHA512:
6
+ metadata.gz: ef9462813278a3a683c64f09aebae8a4f95022949d80900bc2cb9869cea8fcaaebde92192b86320f064ee53afa13ccb875c0280086ffc310216f195473fc6341
7
+ data.tar.gz: adfd48385615b5b8d17ea713dca6c6c6304792baa3ee765b95837a54e3e37191f088a429ade676a3bd6b35ef502bb1ca44d553c28ea5a2ebba4d14aee568d401
@@ -0,0 +1 @@
1
+ service_name: travis-ci
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
+ .yardoc
1
2
  .idea
2
3
  .idea/*
3
4
  rerun.txt
@@ -9,13 +10,17 @@ doc/*
9
10
  *.gem
10
11
  .bundle
11
12
  Gemfile.lock
13
+ Gemfile.*.lock
12
14
  pkg/*
13
15
  test/applicationhost.config
14
16
  .rvmrc
17
+ .ruby-version
18
+ .ruby-gemset
15
19
  .DS_Store
16
20
  *ReSharper*
17
21
  *.suo
18
22
  obj
19
- App_Data/
20
23
  *.pdb
21
- test/RubyODataService/RubyODataService/bin/*.xml
24
+ test/RubyODataService/RubyODataService/bin/*.xml
25
+ test/RubyODataService/RubyODataService/App_Data/*.sdf
26
+ coverage/*
@@ -0,0 +1,10 @@
1
+ if Gem::Version.new(RUBY_VERSION) > Gem::Version.new('1.9') && ENV['COVERAGE']
2
+ require 'simplecov'
3
+ require 'coveralls'
4
+
5
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
6
+ SimpleCov::Formatter::HTMLFormatter
7
+ ]
8
+
9
+ SimpleCov.start
10
+ end
@@ -1,4 +1,10 @@
1
- rvm:
2
- - 1.8.7
3
- - 1.9.2
4
- script: "bundle exec rake spec"
1
+ matrix:
2
+ include:
3
+ # - rvm: 1.8.7
4
+ # gemfile: gemfiles/Gemfile.ruby187
5
+ - rvm: 1.9.3
6
+ gemfile: Gemfile
7
+ - rvm: 2.0.0
8
+ gemfile: Gemfile
9
+
10
+ script: "bundle exec rake test_with_coveralls"
@@ -0,0 +1,6 @@
1
+ --no-cache
2
+ --verbose
3
+ --markup markdown
4
+ --readme README.md
5
+ --hide-void-return
6
+ lib/**/*.rb
@@ -0,0 +1,157 @@
1
+ # ruby_odata Change Log
2
+
3
+ ### 0.0.1
4
+ * New Features
5
+ * Basic CRUD Operations
6
+ * Query Enhancement: Filters
7
+ * Query Enhancement: Expands
8
+
9
+ ### 0.0.2
10
+ * New Features
11
+ * Query Enhancement: Order By (both desc and asc)
12
+
13
+ ### 0.0.3
14
+ * Bug Fixes
15
+ * Rearranged code to match the gem name. Things were mismatched between odata_ruby and ruby_odata.
16
+
17
+ ### 0.0.4
18
+ * New Features
19
+ * Query Enhancement: skip
20
+ * Query Enhancement: top
21
+ * Ability to perform paging using skip and top together
22
+ * Updated README with examples for order_by, skip, and top
23
+
24
+ ### 0.0.5
25
+ * Bug Fixes
26
+ * Works with Ruby 1.9.1
27
+ * Works with ActiveSupport 3.0.0.beta4
28
+
29
+ ### 0.0.6
30
+ * New Features
31
+ * Ability to batch saves (Adds, Updates, Deletes); this will help save on network chatter
32
+
33
+ ### 0.0.7
34
+ * New Features
35
+ * Complex Types are now supported
36
+ * Support for Edm.Int16, Edm.Int32, Edm.Int64
37
+ * Support for Edm.Decimal
38
+ * Support for Edm.DateTime
39
+
40
+ ### 0.0.8
41
+ * New Features
42
+ * Basic HTTP Authentication (thanks J.D. Mullin)
43
+ * Modified cucumber tests to setup the test database so you no longer need to copy them yourself
44
+ * Support for nullable elements returned from the Data Service (m:null ="true")
45
+ * Bug Fixes
46
+ * ActiveSupport 2.3.x (tested 2.3.11) and 3.0.x (tested 3.0.4) are now supported
47
+ * Works with Ruby 1.9.2
48
+
49
+ ### 0.0.9
50
+ * New Features
51
+ * Support for self-signed SSL certificates (thanks J.D. Mullin)
52
+ * Refactored building classes/collections to only make one call to the service
53
+ * Added support for a WCF service with lowercase entities (reported by Klaus Rohe)
54
+ * Bug Fixes
55
+ * Fixed issue with passing a service URL with a trailing slash
56
+ * Other
57
+ * Cleaned up testing by adding a default task to the Rakefile that runs RSpec and Cucumber
58
+
59
+ ### 0.0.10
60
+ * New Features
61
+ * Added the ability to pass additional parameters that are appended to the query string for requests
62
+ * Added initial support for feed customizations (SyndicationTitle and SyndicationSummary)
63
+ * Enhanced ruby_odata's awareness of classes based on the metadata instead of relying on results that are returned
64
+ * Bug Fixes
65
+ * Fixed issues with nested collections (eager loading)
66
+ * Handled ArgumentError on the Time.parse for older versions of Ruby; used DateTime.parse instead if Time.parse fails
67
+ * Removed the camelize method call when building the root URL for collections (Reported by mkoegel, issue #3 on github)
68
+ * Handled building results (classes) where the category element is missing but there is a title element instead. (Reported by mkoegel, issue #3 on github in the comments)
69
+ * Other
70
+ * Change HTTP port to 8989 since 8888 conflicts with the Intel AppStore
71
+ * Refactored service step for HTTP calls where the service address is defined within the step making it easier to make changes in the future.
72
+
73
+ ### 0.1.0
74
+ * **BREAKING CHANGES**
75
+ * Previously the ruby_odata `Service.execute` and `Service.save_changes` used to return a single entity object if there was only one result returned. Now, the results are always an Enumerable (except in the case of boolean results like a delete), so if you just need one result, use the `first` method on the result set
76
+ * New Features
77
+ * Support for partial results (thanks arienmalec)
78
+ * Added support for single layer inheritance (thanks to [Scott](http://odetocode.com/Blogs/scott/archive/2010/07/11/odata-and-ruby.aspx))
79
+ * Added support for querying links (see [Issue 10](https://github.com/visoft/ruby_odata/issues/10))
80
+ * Added support for adding links between entities (add_link)
81
+ * Added support for lazy loading
82
+ * Added a convenience method (`first`) for accessing a single result by id
83
+ * Added basic reflection of the entity model via the ruby_odata service
84
+ * Added the ability to create ruby_odata models in a specified namespace to prevent conflicts with local models
85
+ * Added the ability to call function imports exposed by the WCF Data Service
86
+ * Other
87
+ * Changed the test project (for Cucumber integration tests) to use SQL Compact 4, Entity Framework 4.1, and WCF Data Services October 2011 CTP
88
+ * Added [Pickle](https://github.com/ianwhite/pickle) integration to simplify Cucumber step definitions
89
+
90
+ ### 0.1.1
91
+ * New Features
92
+ * Added the `count` method (to `QueryBuilder`) for returning a count from an OData service
93
+ * Added the `navigate` method (to `QueryBuilder`) in order to handle filtering of children
94
+
95
+ * Bug Fixes
96
+ * Escaped IDs in queries where the ID is a string with spaces
97
+
98
+ * Other
99
+ * Goodbye RDoc; Hello Markdown/YARD
100
+ * Refactored exceptions to use proper error classes
101
+ * Integrated [Guard](https://github.com/guard/guard) into the test suite for continuous testing
102
+ * Integrated [VCR](https://github.com/myronmarston/vcr) into test suite in order to run Cucumber steps without running the test server.
103
+
104
+ ### 0.1.2
105
+ * New Features
106
+ * Added support for nokogiri >= 1.5.1 while maintaining backwards compatibility for >=1.4.2
107
+ * Backports requirement is now for >= 2.3.0
108
+ * Added the ability to pass in :rest_options to the service constructor within the options hash.
109
+
110
+ * Bug Fixes
111
+ * Prevented `svc.load_property` from mutating the obj's metadata uri (thanks [@sillylogger](https://github.com/sillylogger))
112
+
113
+ ### 0.1.3
114
+ * Bug Fixes
115
+ * Persists the additional_params for partial calls (thanks [@levelboy](https://github.com/levelboy))
116
+
117
+ * Other
118
+ * Specified v2.3.4 of the addressable gem since there was a bug when testing ruby_odata against Ruby 1.8.7
119
+
120
+ ### 0.1.4
121
+ * New Features
122
+ * Added option to override content type used for json updates ([issue 29](https://github.com/visoft/ruby_odata/pull/29), thanks [@sigmunau](https://github.com/sigmunau))
123
+
124
+ * Bug Fixes
125
+ * Fixed issue with building a collection of complex types ([issue 26](https://github.com/visoft/ruby_odata/issues/26))
126
+ * A collection of complex types is now returned as an array ([issue 26](https://github.com/visoft/ruby_odata/issues/26))
127
+ * Fixed issue with building a child collection of native types ([issue 27](https://github.com/visoft/ruby_odata/issues/27))
128
+ * Corrected problem with addressable not being referenced
129
+ * Fixed issue with building nested expands ([issue 24](https://github.com/visoft/ruby_odata/pull/24), thanks [@joshuap](https://github.com/joshuap))
130
+ * Edm.Int64 is now formatted as a string, according to odata json spec ([issue 29](https://github.com/visoft/ruby_odata/pull/29), thanks [@sigmunau](https://github.com/sigmunau))
131
+ * Fixed formatting of collections for json output ([issue 29](https://github.com/visoft/ruby_odata/pull/29), thanks [@sigmunau](https://github.com/sigmunau))
132
+ * Fixed handling exceptions that are not http exceptions ([issue 29](https://github.com/visoft/ruby_odata/pull/29), thanks [@sigmunau](https://github.com/sigmunau))
133
+ * Fixed parsing of null strings ([issue 29](https://github.com/visoft/ruby_odata/pull/29), thanks [@sigmunau](https://github.com/sigmunau))
134
+
135
+ * Other
136
+ * Updated the [VCR](https://github.com/myronmarston/vcr) and [WebMock](https://github.com/bblimke/webmock) gems to the latest versions (used for testing)
137
+ * Specified activesupport ~> 3.0 (in gemfiles/ruby187) for Ruby 1.8.7 as activesupport 4 doesn't support Ruby < 1.9.3
138
+
139
+ ## 0.1.5
140
+ * **BREAKING CHANGES**
141
+ * Previously if the OData service threw an exception, ruby_odata threw a generic error with the message that would start with "HTTP Error XXX: ". Instead of the message, the Error that is thrown is an `OData::ServiceError`. It has an `http_code` property on it, thus, the message is now just the text from the OData error without the "HTTP Error XXX: " prefix. This could potentially cause you problems if you were sniffing error messages for the HTTP error code.
142
+
143
+ * New Features
144
+ * Added the ability to query the OData service using the [$select system query option](http://www.odata.org/documentation/odata-v2-documentation/uri-conventions/#48_Select_System_Query_Option_select)
145
+ * Support for Int64 keys ([issue 39](https://github.com/visoft/ruby_odata/issues/39) and [issue 40](https://github.com/visoft/ruby_odata/pull/40), thanks [@nasali](https://github.com/nasali))
146
+ * New property `is_key` added to `PropertyMetadata` in order to determine the key properties for the class (found in the service's `class_metadata` collection)
147
+
148
+ ## 0.1.6
149
+ * **BREAKING CHANGES**
150
+ * Ruby 1.8.7 support has been dropped, thus the backports gem has been removed from the ruby_odata (thanks [@betelgeuse](https://github.com/betelgeuse)) [issue 45 and 46](https://github.com/visoft/ruby_odata/pull/46)
151
+
152
+ * Bug Fixes
153
+ * Check that message is present before including it in the exception. Thanks [@rgould](https://github.com/rgould)
154
+ * Fixed problem with `FunctionImport`, OData dropped the `m:HttpMethod` attribute, see http://www.odata.org/2011/10/actions-in-odata/
155
+
156
+ * Other
157
+ * Changed license to MIT and added it to the gemspec
@@ -0,0 +1,14 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec', :version => 2 do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/ruby_odata/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+ end
9
+
10
+ guard 'cucumber', :all_after_pass => false, :all_on_start => false do
11
+ watch(%r{^features/.+\.feature$})
12
+ watch(%r{^features/support/.+$}) { 'features' }
13
+ watch(%r{^features/step_definitions/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'features' }
14
+ end
data/LICENSE CHANGED
@@ -1,24 +1,22 @@
1
- Copyright (c) 2010, Visoft, Inc.
2
- All rights reserved.
1
+ Copyright (c) 2010-2013 Visoft, Inc.
3
2
 
4
- Redistribution and use in source and binary forms, with or without
5
- modification, are permitted provided that the following conditions are met:
6
- * Redistributions of source code must retain the above copyright
7
- notice, this list of conditions and the following disclaimer.
8
- * Redistributions in binary form must reproduce the above copyright
9
- notice, this list of conditions and the following disclaimer in the
10
- documentation and/or other materials provided with the distribution.
11
- * Neither the name of Visoft, Inc. nor the
12
- names of its contributors may be used to endorse or promote products
13
- derived from this software without specific prior written permission.
3
+ MIT License
14
4
 
15
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
- DISCLAIMED. IN NO EVENT SHALL VISOFT, INC. BE LIABLE FOR ANY
19
- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,289 @@
1
+ # ruby_odata
2
+
3
+ The **Open Data Protocol** (OData) is a fantastic way to query and update data over standard Web technologies. The ruby_odata library acts as a consumer of OData services.
4
+
5
+ [![Build Status](https://secure.travis-ci.org/visoft/ruby_odata.png)](http://travis-ci.org/visoft/ruby_odata)
6
+
7
+ ## Resources
8
+
9
+ * Source Code (hosted on GitHub): http://github.com/visoft/ruby_odata
10
+ * Documentation (hosted on rdoc.info): http://rdoc.info/projects/visoft/ruby_odata
11
+ * Issue tracking (hosted on GitHub): https://github.com/visoft/ruby_odata/issues
12
+ * Wiki (hosted on GitHub): http://wiki.github.com/visoft/ruby_odata/
13
+ * Gem (hosted on Gemcutter): http://gemcutter.org/gems/ruby_odata
14
+ * Blog articles:
15
+ * [Introducing a Ruby OData Client Library](http://bit.ly/IntroRubyOData)
16
+ * [Ruby OData Update v0.0.7](http://bit.ly/ruby_odata007)
17
+ * [Ruby OData Update v0.0.8](http://bit.ly/ruby_odata008)
18
+ * [Ruby OData Update v0.0.10](http://bit.ly/ruby_odata0010)
19
+ * [Major Ruby OData Update v0.1.0](http://bit.ly/ruby_odata010)
20
+
21
+ ## Installation
22
+ You can install ruby_odata as a gem using:
23
+
24
+ gem install ruby_odata
25
+
26
+ ## Usage
27
+
28
+ ### Instantiating the Service
29
+ There are various options that you can pass when creating an instance of the service, these include:
30
+ * username: username for http basic auth
31
+ * password: password for http basic auth
32
+ * verify_ssl: false if no verification, otherwise mode (OpenSSL::SSL::VERIFY_PEER is default)
33
+ * rest_options: a hash of options that will be passed on to the rest-client calls. The passed in rest_options will be merged with the standard options that are set (username, password, and verify_ssl). This will allow you to set additional SSL settings. See [the rest-client docs](http://rubydoc.info/gems/rest-client/1.6.7/file/README.rdoc#SSL_Client_Certificates) for more information. Note, the options that you pass in will take precedence over the previous 3 options, so it is possible to set/override the username, password, and verify_ssl options directly with this hash.
34
+ * additional_params: a hash of query string params that will be passed on all calls (query, new, update, delete, batch)
35
+ * namespace: a string based namespace to create your objects in. You can specify the namespace using periods as separators (like .NET, for example `VisoftInc.Sample.Models`) or using double colons as separators (like Ruby `VisoftInc::Sample::Models`). By providing a namespace you can prevent naming collisions in your applications.
36
+
37
+ ### Adding
38
+ When you point at a service, an AddTo<EntityName> method is created for you. This method takes in the new entity to create. To commit the change, you need to call the save_changes method on the service. To add a new category for example, you would simply do the following:
39
+
40
+ require 'ruby_odata'
41
+
42
+ svc = OData::Service.new "http://127.0.0.1:8989/SampleService/RubyOData.svc"
43
+ new_category = Category.new
44
+ new_category.Name = "Sample Category"
45
+ svc.AddToCategories(new_category)
46
+ category = svc.save_changes
47
+ puts category.to_json
48
+
49
+ ### Updating
50
+ To update an object, simply pass the modified object to the update_object method on the service. Updating, like adding requires you to call save_changes in order to persist the change. For example:
51
+
52
+ require 'ruby_odata'
53
+
54
+ svc = OData::Service.new "http://127.0.0.1:8989/SampleService/RubyOData.svc"
55
+ new_category = Category.new
56
+ new_category.Name = "Sample Category"
57
+ svc.AddToCategories(new_category)
58
+ category = svc.save_changes
59
+ puts category.to_json
60
+
61
+ category.Name = 'Updated Category'
62
+ svc.update_object(category)
63
+ result = svc.save_changes
64
+ puts "Was the category updated? #{result}"
65
+
66
+ ### Deleting
67
+ Deleting an object involves passing the tracked object to the delete_object method on the service. Deleting is another function that involves the save_changes method (to commit the change back to the server). In this example, we'll add a category and then delete it.
68
+
69
+ require 'ruby_odata'
70
+
71
+ svc = OData::Service.new "http://127.0.0.1:8989/SampleService/RubyOData.svc"
72
+ new_category = Category.new
73
+ new_category.Name = "Sample Category"
74
+ svc.AddToCategories(new_category)
75
+ category = svc.save_changes
76
+ puts category.to_json
77
+
78
+ svc.delete_object(category)
79
+ result = svc.save_changes
80
+ puts "Was the category deleted? #{result}"
81
+
82
+ ### Add Link
83
+ Adding a linkage between entities can now be performed outside of creation or modification of the objects. See the [OData documents](http://www.odata.org/developers/protocols/operations#CreatingLinksbetweenEntries) for more details.
84
+ To add a link between entities, simply call the `add_link` method on the Service passing the parent object, the name of the navigation property, and the child object. Like all save operations, you need to call `save_changes` to persist the changes.
85
+
86
+ svc.add_link(<Parent>, <Navigation Property Name>, <Child>)
87
+ svc.save_changes
88
+
89
+ ### Querying
90
+ Querying is easy, for example to pull all the categories from the SampleService, you simply can run:
91
+
92
+ require 'ruby_odata'
93
+
94
+ svc = OData::Service.new "http://127.0.0.1:8989/SampleService/RubyOData.svc"
95
+ svc.Categories
96
+ categories = svc.execute
97
+ puts categories.to_json
98
+
99
+ You can also expand, add filters, order, skip records, and take only the top X records to the query before executing it. For example:
100
+
101
+ ### Expanding
102
+ Expanding allows you to eagerly load other objects that are children of the root.
103
+ You can use more than one expand on a query.
104
+ For expanding grandchild and lower entities, you must pass in the full path from the root, for example `Products.expand('Orders').expand('Orders/LineItems')`
105
+
106
+ # Without expanding the query
107
+ svc.Products(1)
108
+ prod1 = svc.execute
109
+ puts "Without expanding the query"
110
+ puts "#{prod1.to_json}\n"
111
+
112
+ # With expanding the query
113
+ svc.Products(1).expand('Category')
114
+ prod1 = svc.execute
115
+ puts "With expanding the query"
116
+ puts "#{prod1.to_json}\n"
117
+
118
+ ### Lazy Loading
119
+ If you want to implement lazy loading, the ruby_odata `Service` allows you to perform this. You simply need to call the `load_property` method on the `Service` passing in the object and the navigation property to fill.
120
+
121
+ # Without expanding the query
122
+ svc.Products(1)
123
+ prod1 = svc.execute.first
124
+ puts "#{prod1.to_json}\n"
125
+
126
+ # Use load_property for lazy loading
127
+ svc.load_property(prod1, "Category")
128
+ puts "#{prod1.to_json}\n"
129
+
130
+ ### Filtering
131
+ The syntax for filtering can be found on the [OData Protocol URI Conventions](http://www.odata.org/developers/protocols/uri-conventions#FilterSystemQueryOption) page.
132
+ You can use more than one filter, if you call the filter method multiple times it will before an AND.
133
+
134
+ # You can access by ID (but that isn't is a filter)
135
+ # The syntax is just svc.ENTITYNAME(ID) which is shown in the expanding examples above
136
+
137
+ svc.Products.filter("Name eq 'Product 2'")
138
+ prod = svc.execute
139
+ puts "Filtering on Name eq 'Product 2'"
140
+ puts "#{prod.to_json}"
141
+
142
+ Note you can pass more than one filter in the string, for example (querying Netflix):
143
+
144
+ svc.Titles.filter("Rating eq 'PG' and ReleaseYear eq 1980")
145
+
146
+ Filters can also be chained, by doing this you will create an "and" filter (just like the last example) when it is passed to the server.
147
+
148
+ svc.Titles.filter("Rating eq 'PG'").filter("ReleaseYear eq 1980")
149
+
150
+
151
+ ### Combining Expanding and Filtering
152
+ The query operations follow a [fluent interface](http://en.wikipedia.org/wiki/Fluent_interface), although they can be added by themselves as well as chained
153
+
154
+ svc.Products.filter("Name eq 'Product 2'").expand("Category")
155
+ prod = svc.execute
156
+ puts "Filtering on Name eq 'Product 2' and expanding"
157
+ puts "#{prod.to_json}"
158
+
159
+ ### Order By
160
+ You can order the results by properties of your choice, either ascending or descending.
161
+ Order by are similar to `expands` in that you can use more than one of them on a query.
162
+ For expanding grandchild and lower entities, you must pass in the full path from the root like would do on an `expand`
163
+
164
+ svc.Products.order_by("Name")
165
+ products = svc.execute
166
+
167
+ # Specifically requesting descending
168
+ svc.Products.order_by("Name desc")
169
+ products = svc.execute
170
+
171
+ # Specifically requesting ascending
172
+ svc.Products.order_by("Name asc")
173
+ products = svc.execute
174
+
175
+ Like the fiter method, order_by statements can also be chained like so:
176
+
177
+ svc.Products.order_by("Name asc").order_by("Price desc")
178
+
179
+
180
+ ### Skip
181
+ Skip allows you to skip a number of records when querying. This is often used for paging along with `top`.
182
+
183
+ svc.Products.skip(5)
184
+ products = svc.execute # => skips the first 5 items
185
+
186
+ ### Top
187
+ Top allows you only retrieve the top X number of records when querying. This is often used for paging along with `skip`.
188
+
189
+ svc.Products.top(5)
190
+ products = svc.execute # => returns only the first 5 items
191
+
192
+ ### Navigation Property Links Only Query
193
+ OData allows you to [query navigation properties and only return the links for the entities](http://www.odata.org/developers/protocols/uri-conventions#AddressingLinksBetweenEntries) (instead of the data).
194
+ **Note**: You cannot use the `links` method and the `count` method in the same query
195
+
196
+ svc.Categories(1).links("Products")
197
+ product_links = svc.execute # => returns URIs for the products under the Category with an ID of 1
198
+
199
+ ### Advanced Navigation Property Functions
200
+ There are instances where you may need to navigate down a level in order to form the proper query.
201
+ Take for example [Netflix's OData Service](http://developer.netflix.com/docs/oData_Catalog/) and their `Genres` Entity Collection, where you can access a Navigation Property (in this case `Titles` through the `Genre` and filter on it:
202
+
203
+ http://odata.netflix.com/Catalog/Genres('Horror%20Movies')/Titles?$filter=Name%20eq'Halloween'
204
+
205
+ In order to do this within ruby_odata, you can use the `navigate` method of the `QueryBuilder` to drill-down into the Navigation Property. This will allow you to perform `filter`s, `skip`s, `orderby`s, etc. against the children.
206
+
207
+ svc = OData::Service.new("http://odata.netflix.com/Catalog")
208
+ svc.Genres("'Horror Movies'").navigate("Titles").filter("Name eq 'Halloween'")
209
+ movies = svc.execute
210
+ movies.each { |m| puts m.Name }
211
+
212
+ ### Count
213
+ Sometimes all you want to do is count records, for that, you can use the `count` method.
214
+ This method can be combined with other options, such as `filter` but cannot be combined with the `links` method.
215
+
216
+ svc.Products.count
217
+ puts svc.execute # => 2
218
+
219
+ ### Partial feeds
220
+ OData allows services to do server-side paging in Atom by defining a next link. The default behavior is to repeatedly consume partial feeds until the result set is complete.
221
+
222
+ svc.Partials
223
+ results = svc.execute # => retrieves all results in the Partials collection
224
+
225
+ If desired (e.g., because the result set is too large to fit in memory), explicit traversal of partial results can be requested via options:
226
+
227
+ svc = OData::Service.new "http://example.com/Example.svc", { :eager_partial => false }
228
+ svc.Partials
229
+ results = svc.execute # => retrieves the first set of results returned by the server
230
+ if svc.partial? # => true if the last result set was a partial result set (i.e., had a next link)
231
+ results.concat svc.next # => retrieves the next set of results
232
+ end
233
+ while svc.partial? # => to retrieve all partial result sets
234
+ results.concat svc.next
235
+ end
236
+
237
+ ### Authentication
238
+ Basic HTTP Authentication is supported via sending a username and password as service constructor arguments:
239
+
240
+ require 'ruby_odata'
241
+
242
+ svc = OData::Service.new "http://127.0.0.1:8989/SampleService/RubyOData.svc", { :username => "bob", :password=> "12345" }
243
+
244
+ ### SSL/https Certificate Verification
245
+ The certificate verification mode can be passed in the options hash via the :verify_ssl key. For example, to ignore verification in order to use a self-signed certificate:
246
+
247
+ require 'ruby_odata'
248
+
249
+ svc = OData::Service.new "https://127.0.0.1:44300/SampleService/RubyOData.svc", { :verify_ssl => false }
250
+
251
+ Or an OpenSSL integer constant can be passed as well:
252
+
253
+ require 'ruby_odata'
254
+
255
+ svc = OData::Service.new "https://127.0.0.1:44300/SampleService/RubyOData.svc", { :verify_ssl => OpenSSL::SSL::VERIFY_PEER }
256
+
257
+ Default verification is OpenSSL::SSL::VERIFY_PEER. Note due to the way Ruby's Request object implements certificate checking, you CAN NOT pass OpenSSL::SSL::VERIFY_NONE, you must instead pass a boolean false.
258
+
259
+ ## Function Imports / Custom Service Methods
260
+ Function Imports are custom service methods exposed by the WCF Data Service. Each function import will be created as a method on the ruby_odata Service. When you make a call to one of these, they return a result immediately without the need to call `execute` or `save_changes`.
261
+
262
+ ## Reflection
263
+ Instead of relying on looking at the EDMX directly, ruby_odata allows you to perform basic reflection on objects
264
+ ### Service Level Methods
265
+ * **Collections** - You can look at the collections exposed by a service by accessing the `collections` method, which is a hash. The key is the name of the collection and the value is the hash with `edmx_type`, which returns the name of the type from the EDMX and `:type`, which is the local type that is created for you
266
+ * **Classes** - To see the generated classes, you can utilize the `classes` method on the service. The return result is a hash where the key is the class name and the value is the class type.
267
+ * **Function Imports** - You can find any function import (custom service methods) exposed by the service by accessing the `function_imports` method. This is a hash where the key is the Function Import name and the value is metadata about the Function Import.
268
+
269
+ ### Class Level Methods
270
+ * **Properties** - You can call the class method `properties` on a generated class to see the method (properties) that were created. The returned result is a hash where the key is the property name and the value is metadata for the property like if it is nullable, the EDM Type, etc.
271
+
272
+ ## Tests
273
+ All of the tests are written using Cucumber going against a sample service (Found in test/RubyODataService/RubyODataService/*).
274
+ The SampleService is an ASP.NET Web Site running a SQL Compact 4 Database, which gets generated at runtime, as well as the ADO.NET Entity Framework 4.1 and WCF Data Services October 2011 CTP. The reason for the CTP is that WCF Data Services currently shipping with .NET 4 doesn't support Entity Framework 4.1's "Code First" approach (e.g. no EDMX, all POCOs)
275
+ In order to run the tests, you need to spin up IIS running a virtual directory of SampleService on port 8989 (http://localhost:8989/SampleService) and another instance running on port 44300.
276
+
277
+ **NOTE** The ports (8989 and 44300) and webserver (localhost by default) here are customizable thanks to `/features/contants.rb`. Take a look in there for the corresponding environment variables that you can set.
278
+
279
+ The SampleService requires IIS or IIS Express. IIS Express is a free download from Microsoft and the preferred approach to running the application. Once installed, there is a batch file found in /test called "iisExpress x64.bat" that will spin up the appropriate instances needed for the Cucumber tests. There is a also an "iisExpress x86.bat" file for those of you running a 32-bit machine. The only difference is the path to the Program Files directory. Once you run the batch file, the web server will spin up. To stop the server, use 'Q' and then enter or close the command window.
280
+
281
+ If you are having trouble with IIS Express, you may need to perform the following: Upon running the IIS Express installer copy the config folder from the IIS Express installed folder (e.g. c:\Progam Files (x86)\IIS Express\config) to the IIS folder in your home folder (e.g. c:\Users\Administrator\Documents\IISExpress). Within the newly copied config folder, copy the aspnet.config file from the templates\PersonalWebServer\aspnet.config folder into the config folder as well (e.g. c:\Users\Administrator\Documents\IISExpres\config\aspnet.config).
282
+
283
+ If you are testing on a Windows machine, you may encounter a problem with using Cucumber and Ruby 1.9.2. You will get a message when you fire up cucumber about missing msvcrt-ruby18.dll. The fix for this is to make sure you have the [RubyInstaller DevKit](https://github.com/oneclick/rubyinstaller/wiki/Development-Kit) installed, then do the following:
284
+
285
+ gem uninstall json
286
+ gem install json --platform=ruby -v 1.4.6
287
+
288
+ Once the SampleService is running, from the BASE ruby_odata directory, simply type `rake`, which will run the RSpec and Cucumber specs. You can also run them separately `rake spec` for RSpec and `rake features` for Cucumber.
289
+