Permalink
Browse files

Merge branch 'release/v0.1.2'

  • Loading branch information...
2 parents bfd6fb9 + 4798fc0 commit 5290cdc153dc783fdafb379f2400d36026a9db0e @visoft committed Feb 22, 2013
View
9 CHANGELOG.md
@@ -100,3 +100,12 @@
* Refactored exceptions to use proper error classes
* Integrated [Guard](https://github.com/guard/guard) into the test suite for continuous testing
* Integrated [VCR](https://github.com/myronmarston/vcr) into test suite in order to run Cucumber steps without running the test server.
+
+### 0.1.2
+* New Features
+ * Added support for nokogiri >= 1.5.1 while maintaining backwards compatibility for >=1.4.2
+ * Backports requirement is now for >= 2.3.0
+ * Added the ability to pass in :rest_options to the service constructor within the options hash.
+
+* Bug Fixes
+ * Prevented `svc.load_property` from mutating the obj's metadata uri (thanks [@sillylogger](https://github.com/sillylogger))
View
4 README.md
@@ -16,6 +16,7 @@ The **Open Data Protocol** (OData) is a fantastic way to query and update data o
* [Ruby OData Update v0.0.7](http://bit.ly/ruby_odata007)
* [Ruby OData Update v0.0.8](http://bit.ly/ruby_odata008)
* [Ruby OData Update v0.0.10](http://bit.ly/ruby_odata0010)
+ * [Major Ruby OData Update v0.1.0](http://bit.ly/ruby_odata010)
## Installation
You can install ruby_odata as a gem using:
@@ -29,6 +30,7 @@ There are various options that you can pass when creating an instance of the ser
* username: username for http basic auth
* password: password for http basic auth
* verify_ssl: false if no verification, otherwise mode (OpenSSL::SSL::VERIFY_PEER is default)
+* 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.
* additional_params: a hash of query string params that will be passed on all calls (query, new, update, delete, batch)
* 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.
@@ -276,6 +278,8 @@ In order to run the tests, you need to spin up IIS running a virtual directory o
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.
+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).
+
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:
gem uninstall json
View
6 lib/ruby_odata/helpers.rb
@@ -17,5 +17,11 @@ def self.uri_escape(*args)
URI.escape(*args)
end
end
+
+ # Nokogiri changed how it handles namespaced attributes with v1.5.1, this is for backwards compatibility to >= 1.4.2
+ # Nokogiri now >=1.5.1 requires the namespace prefix is used
+ def self.get_namespaced_attribute(node, attr_name, prefix)
+ return node["#{prefix}:#{attr_name}"] || node[attr_name]
+ end
end
end
View
5 lib/ruby_odata/property_metadata.rb
@@ -24,8 +24,9 @@ def initialize(property_element)
@name = property_element['Name']
@type = property_element['Type']
@nullable = ((property_element['Nullable'] && property_element['Nullable'] == "true") || property_element.name == 'NavigationProperty') || false
- @fc_target_path = property_element['FC_TargetPath']
- @fc_keep_in_content = (property_element['FC_KeepInContent']) ? (property_element['FC_KeepInContent'] == "true") : nil
+ @fc_target_path = Helpers.get_namespaced_attribute(property_element, 'FC_TargetPath', 'm')
+ keep_in_content = Helpers.get_namespaced_attribute(property_element, 'FC_KeepInContent', 'm')
+ @fc_keep_in_content = (keep_in_content) ? (keep_in_content == "true") : nil
@nav_prop = property_element.name == 'NavigationProperty'
end
end
View
2 lib/ruby_odata/query_builder.rb
@@ -6,6 +6,8 @@ module OData
# svc.Categories
# The *Categories* method would return a QueryBuilder
class QueryBuilder
+ attr_accessor :additional_params
+
# Creates a new instance of the QueryBuilder class
#
# @param [String] root entity collection to query against
View
16 lib/ruby_odata/service.rb
@@ -9,6 +9,7 @@ class Service
# @option options [String] :username for http basic auth
# @option options [String] :password for http basic auth
# @option options [Object] :verify_ssl false if no verification, otherwise mode (OpenSSL::SSL::VERIFY_PEER is default)
+ # @option options [Hash] :rest_options a hash of rest-client options that will be passed to all RestClient::Resource.new calls
# @option options [Hash] :additional_params a hash of query string params that will be passed on all calls
# @option options [Boolean, true] :eager_partial true if queries should consume partial feeds until the feed is complete, false if explicit calls to next must be performed
def initialize(service_uri, options = {})
@@ -172,6 +173,7 @@ def set_options!(options)
@options[:eager_partial] = true
end
@rest_options = { :verify_ssl => get_verify_mode, :user => @options[:username], :password => @options[:password] }
+ @rest_options.merge!(options[:rest_options] || {})
@additional_params = options[:additional_params] || {}
@namespace = options[:namespace]
end
@@ -472,13 +474,13 @@ def build_save_uri(operation)
uri
end
def build_add_link_uri(operation)
- uri = "#{operation.klass.send(:__metadata)[:uri]}"
+ uri = operation.klass.send(:__metadata)[:uri].dup
uri << "/$links/#{operation.klass_name}"
uri << "?#{@additional_params.to_query}" unless @additional_params.empty?
uri
end
def build_resource_uri(operation)
- uri = operation.klass.send(:__metadata)[:uri]
+ uri = operation.klass.send(:__metadata)[:uri].dup
uri << "?#{@additional_params.to_query}" unless @additional_params.empty?
uri
end
@@ -488,7 +490,7 @@ def build_batch_uri
uri
end
def build_load_property_uri(obj, property)
- uri = obj.__metadata[:uri]
+ uri = obj.__metadata[:uri].dup
uri << "/#{property}"
uri
end
@@ -630,7 +632,7 @@ def build_batch_operation(operation, changeset_num)
# Complex Types
def complex_type_to_class(complex_type_xml)
- klass_name = qualify_class_name(complex_type_xml.attr('type').split('.')[-1])
+ klass_name = qualify_class_name(Helpers.get_namespaced_attribute(complex_type_xml, 'type', 'm').split('.')[-1])
klass = @classes[klass_name].new
# Fill in the properties
@@ -663,8 +665,8 @@ def parse_date(sdate)
# Parses a value into the proper type based on an xml property element
def parse_value(property_xml)
- property_type = property_xml.attr('type')
- property_null = property_xml.attr('null')
+ property_type = Helpers.get_namespaced_attribute(property_xml, 'type', 'm')
+ property_null = Helpers.get_namespaced_attribute(property_xml, 'null', 'm')
# Handle a nil property type, this is a string
return property_xml.content if property_type.nil?
@@ -764,4 +766,4 @@ def singular?(value)
end
end
-end # module OData
+end # module OData
View
2 lib/ruby_odata/version.rb
@@ -1,5 +1,5 @@
# The ruby_odata namespace
module OData
# The current version of ruby_odata
- VERSION = "0.1.1"
+ VERSION = "0.1.2"
end
View
2 ruby_odata.gemspec
@@ -18,7 +18,7 @@ Gem::Specification.new do |s|
s.add_dependency("activesupport", ">= 3.0.0")
s.add_dependency("rest-client", ">= 1.5.1")
s.add_dependency("nokogiri", ">= 1.4.2")
- s.add_dependency("backports", "~> 2.3.0")
+ s.add_dependency("backports", ">= 2.3.0")
s.add_development_dependency("rake", "0.9.2")
s.add_development_dependency("rspec", "~> 2.11.0")
View
4 spec/property_metadata_spec.rb
@@ -28,13 +28,13 @@ module OData
property_metadata.nullable.should eq false
end
it "parses an EDMX property with the fc_target_path and fc_keep_in_content attribute" do
- property_element = RSpecSupport::ElementHelpers.string_to_element('<Property Name="Title" Type="Edm.String" Nullable="true" m:FC_TargetPath="SyndicationTitle" m:FC_ContentKind="text" m:FC_KeepInContent="false" />')
+ property_element = RSpecSupport::ElementHelpers.string_to_element('<Property xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" Name="Title" Type="Edm.String" Nullable="true" m:FC_TargetPath="SyndicationTitle" m:FC_ContentKind="text" m:FC_KeepInContent="false" />')
property_metadata = PropertyMetadata.new property_element
property_metadata.fc_target_path.should eq "SyndicationTitle"
property_metadata.fc_keep_in_content.should eq false
end
it "parses an EDMX property where fc_keep_in_content is true" do
- property_element = RSpecSupport::ElementHelpers.string_to_element('<Property Name="Title" Type="Edm.String" Nullable="true" m:FC_TargetPath="SyndicationTitle" m:FC_ContentKind="text" m:FC_KeepInContent="true" />')
+ property_element = RSpecSupport::ElementHelpers.string_to_element('<Property xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" Name="Title" Type="Edm.String" Nullable="true" m:FC_TargetPath="SyndicationTitle" m:FC_ContentKind="text" m:FC_KeepInContent="true" />')
property_metadata = PropertyMetadata.new property_element
property_metadata.fc_keep_in_content.should eq true
end
View
17 spec/query_builder_spec.rb
@@ -88,6 +88,23 @@ module OData
end
end
+ describe "additional_parameters" do
+ it "should be able to be added at any time" do
+ builder = QueryBuilder.new "PollingLocations"
+ builder.filter("Address/Zip eq 45693")
+ builder.expand("Election")
+ builder.additional_params[:foo] = "bar"
+ builder.query.should eq "PollingLocations?$expand=Election&$filter=Address%2FZip+eq+45693&foo=bar"
+ end
+
+ it "should not overwrite what is already there" do
+ builder = QueryBuilder.new "Products", { :x=>1, :y=>2 }
+ builder.top(10)
+ builder.additional_params[:foo] = "bar"
+ builder.query.should eq "Products?$top=10&foo=bar&x=1&y=2"
+ end
+ end
+
describe "#query" do
it "should encode spaces in IDs" do
builder = QueryBuilder.new "Categories('Cool Stuff')"
View
34 spec/service_spec.rb
@@ -36,6 +36,23 @@ module OData
a_request(:get, "http://test.com/test.svc/$metadata?x=1&y=2").should have_been_made
end
end
+
+ describe "rest-client options" do
+ before(:each) do
+ # Required for the build_classes method
+ stub_request(:get, /http:\/\/test\.com\/test\.svc\/\$metadata(?:\?.+)?/).
+ with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
+ to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/edmx_empty.xml", __FILE__)), :headers => {})
+ end
+ it "should accept in options that will be passed to the rest-client lib" do
+ svc = OData::Service.new "http://test.com/test.svc/", { :rest_options => { :ssl_ca_file => "ca_certificate.pem" } }
+ svc.options[:rest_options].should eq Hash[:ssl_ca_file => "ca_certificate.pem"]
+ end
+ it "should merge the rest options with the built in options" do
+ svc = OData::Service.new "http://test.com/test.svc/", { :rest_options => { :ssl_ca_file => "ca_certificate.pem" } }
+ svc.instance_variable_get(:@rest_options).should eq Hash[:verify_ssl => 1, :user => nil, :password => nil, :ssl_ca_file => "ca_certificate.pem"]
+ end
+ end
end
describe "additional query string parameters" do
before(:each) do
@@ -466,6 +483,15 @@ module OData
category.Products[0].Id.should eq 1
category.Products[1].Id.should eq 2
end
+
+ it "should not mutate the object's metadata" do
+ svc = OData::Service.new "http://test.com/test.svc/"
+ svc.Products(1)
+ product = svc.execute.first
+ original_metadata = product.__metadata.to_json
+ svc.load_property(product, "Category")
+ product.__metadata.to_json.should == original_metadata
+ end
end
describe "find, create, add, update, and delete" do
@@ -704,6 +730,12 @@ module OData
end
end
end
+
+ describe "restful options" do
+ it "should allow " do
+
+ end
+ end
end
describe_private OData::Service do
@@ -723,4 +755,4 @@ module OData
end
end
end
-end
+end

0 comments on commit 5290cdc

Please sign in to comment.