ruby_odata 0.1.3 → 0.1.4
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.
- data/.coveralls.yml +1 -0
 - data/.gitignore +4 -0
 - data/.simplecov +10 -0
 - data/.travis.yml +10 -5
 - data/CHANGELOG.md +21 -1
 - data/Rakefile +19 -2
 - data/features/step_definitions/service_steps.rb +2 -58
 - data/features/support/env.rb +6 -1
 - data/gemfiles/Gemfile.ruby187 +6 -0
 - data/lib/ruby_odata.rb +1 -0
 - data/lib/ruby_odata/class_builder.rb +14 -0
 - data/lib/ruby_odata/service.rb +65 -35
 - data/lib/ruby_odata/version.rb +1 -1
 - data/ruby_odata.gemspec +4 -2
 - data/spec/fixtures/ms_system_center/edmx_ms_system_center.xml +1645 -0
 - data/spec/fixtures/ms_system_center/hardware_profiles.xml +61 -0
 - data/spec/fixtures/ms_system_center/virtual_machines.xml +175 -0
 - data/spec/fixtures/ms_system_center/vm_templates.xml +1193 -0
 - data/spec/fixtures/nested_expands/edmx_northwind.xml +557 -0
 - data/spec/fixtures/nested_expands/northwind_products_category_expands.xml +774 -0
 - data/spec/service_spec.rb +147 -3
 - data/spec/spec_helper.rb +3 -0
 - metadata +55 -8
 
    
        data/.coveralls.yml
    ADDED
    
    | 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            service_name: travis-ci
         
     | 
    
        data/.gitignore
    CHANGED
    
    | 
         @@ -10,9 +10,12 @@ doc/* 
     | 
|
| 
       10 
10 
     | 
    
         
             
            *.gem
         
     | 
| 
       11 
11 
     | 
    
         
             
            .bundle
         
     | 
| 
       12 
12 
     | 
    
         
             
            Gemfile.lock
         
     | 
| 
      
 13 
     | 
    
         
            +
            Gemfile.*.lock
         
     | 
| 
       13 
14 
     | 
    
         
             
            pkg/*
         
     | 
| 
       14 
15 
     | 
    
         
             
            test/applicationhost.config
         
     | 
| 
       15 
16 
     | 
    
         
             
            .rvmrc
         
     | 
| 
      
 17 
     | 
    
         
            +
            .ruby-version
         
     | 
| 
      
 18 
     | 
    
         
            +
            .ruby-gemset
         
     | 
| 
       16 
19 
     | 
    
         
             
            .DS_Store
         
     | 
| 
       17 
20 
     | 
    
         
             
            *ReSharper*
         
     | 
| 
       18 
21 
     | 
    
         
             
            *.suo
         
     | 
| 
         @@ -20,3 +23,4 @@ obj 
     | 
|
| 
       20 
23 
     | 
    
         
             
            *.pdb
         
     | 
| 
       21 
24 
     | 
    
         
             
            test/RubyODataService/RubyODataService/bin/*.xml
         
     | 
| 
       22 
25 
     | 
    
         
             
            test/RubyODataService/RubyODataService/App_Data/*.sdf
         
     | 
| 
      
 26 
     | 
    
         
            +
            coverage/*
         
     | 
    
        data/.simplecov
    ADDED
    
    
    
        data/.travis.yml
    CHANGED
    
    | 
         @@ -1,5 +1,10 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
             
     | 
| 
       2 
     | 
    
         
            -
               
     | 
| 
       3 
     | 
    
         
            -
             
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
      
 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"
         
     | 
    
        data/CHANGELOG.md
    CHANGED
    
    | 
         @@ -115,4 +115,24 @@ 
     | 
|
| 
       115 
115 
     | 
    
         
             
                * Persists the additional_params for partial calls (thanks [@levelboy](https://github.com/levelboy))
         
     | 
| 
       116 
116 
     | 
    
         | 
| 
       117 
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
         
     | 
| 
      
 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 
     | 
    
         
            +
             
     | 
    
        data/Rakefile
    CHANGED
    
    | 
         @@ -13,6 +13,23 @@ Cucumber::Rake::Task.new(:features) do |t| 
     | 
|
| 
       13 
13 
     | 
    
         
             
              t.cucumber_opts = "features --format progress"
         
     | 
| 
       14 
14 
     | 
    
         
             
            end
         
     | 
| 
       15 
15 
     | 
    
         | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
16 
     | 
    
         
             
            Bundler::GemHelper.install_tasks
         
     | 
| 
       18 
     | 
    
         
            -
            task :default => [:spec, :features]
         
     | 
| 
      
 17 
     | 
    
         
            +
            task :default => [:spec, :features]
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            desc "Run with code coverage"
         
     | 
| 
      
 20 
     | 
    
         
            +
            task :coverage do
         
     | 
| 
      
 21 
     | 
    
         
            +
              ENV['COVERAGE'] = 'true' if Gem::Version.new(RUBY_VERSION) > Gem::Version.new('1.9')
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
              Rake::Task["spec"].execute
         
     | 
| 
      
 24 
     | 
    
         
            +
              Rake::Task["features"].execute
         
     | 
| 
      
 25 
     | 
    
         
            +
            end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            desc "Run test with coveralls"
         
     | 
| 
      
 28 
     | 
    
         
            +
            task :test_with_coveralls =>   [:coverage, 'coveralls_push_workaround']
         
     | 
| 
      
 29 
     | 
    
         
            +
            task :coveralls_push_workaround do
         
     | 
| 
      
 30 
     | 
    
         
            +
              if Gem::Version.new(RUBY_VERSION) > Gem::Version.new('1.9')
         
     | 
| 
      
 31 
     | 
    
         
            +
                require 'coveralls/rake/task'
         
     | 
| 
      
 32 
     | 
    
         
            +
                Coveralls::RakeTask.new
         
     | 
| 
      
 33 
     | 
    
         
            +
                Rake::Task["coveralls:push"].invoke
         
     | 
| 
      
 34 
     | 
    
         
            +
              end
         
     | 
| 
      
 35 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -20,14 +20,6 @@ Given /^a HTTP ODataService exists$/ do 
     | 
|
| 
       20 
20 
     | 
    
         
             
              end
         
     | 
| 
       21 
21 
     | 
    
         
             
            end
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
     | 
    
         
            -
            Given /^a HTTP BasicAuth ODataService exists$/ do
         
     | 
| 
       24 
     | 
    
         
            -
              @service = OData::Service.new(BASICAUTH_URL)
         
     | 
| 
       25 
     | 
    
         
            -
            end
         
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
            Given /^a HTTPS BasicAuth ODataService exists$/ do
         
     | 
| 
       28 
     | 
    
         
            -
              @service = OData::Service.new(HTTPS_BASICAUTH_URL)
         
     | 
| 
       29 
     | 
    
         
            -
            end
         
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
23 
     | 
    
         
             
            Given /^a HTTP BasicAuth ODataService exists using username "([^\"]*)" and password "([^\"]*)"$/ do |username, password|
         
     | 
| 
       32 
24 
     | 
    
         
             
              @service = OData::Service.new(BASICAUTH_URL, { :username => username, :password => password })
         
     | 
| 
       33 
25 
     | 
    
         
             
            end
         
     | 
| 
         @@ -36,14 +28,6 @@ Given /^a HTTP BasicAuth ODataService exists using username "([^\"]*)" and passw 
     | 
|
| 
       36 
28 
     | 
    
         
             
              lambda { @service = OData::Service.new(BASICAUTH_URL, { :username => username, :password => password }) }.should raise_error(msg)
         
     | 
| 
       37 
29 
     | 
    
         
             
            end
         
     | 
| 
       38 
30 
     | 
    
         | 
| 
       39 
     | 
    
         
            -
            Given /^a HTTP BasicAuth ODataService exists it should throw an exception with message containing "([^\"]*)"$/ do |msg|
         
     | 
| 
       40 
     | 
    
         
            -
              lambda { @service = OData::Service.new(BASICAUTH_URL) }.should raise_error(/#{msg}.*/)
         
     | 
| 
       41 
     | 
    
         
            -
            end
         
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
            Given /^a HTTPS BasicAuth ODataService exists it should throw an exception with message containing "([^"]*)"$/ do |msg|
         
     | 
| 
       44 
     | 
    
         
            -
              lambda { @service = OData::Service.new(HTTPS_BASICAUTH_URL) }.should raise_error(/#{msg}.*/)
         
     | 
| 
       45 
     | 
    
         
            -
            end
         
     | 
| 
       46 
     | 
    
         
            -
             
     | 
| 
       47 
31 
     | 
    
         
             
            Given /^a HTTP BasicAuth ODataService exists it should throw an exception with message "([^\"]*)"$/ do |msg|
         
     | 
| 
       48 
32 
     | 
    
         
             
              lambda { @service = OData::Service.new(BASICAUTH_URL) }.should raise_error(msg)
         
     | 
| 
       49 
33 
     | 
    
         
             
            end
         
     | 
| 
         @@ -56,10 +40,6 @@ When /^I call "([^\"]*)" on the service$/ do |method| 
     | 
|
| 
       56 
40 
     | 
    
         
             
              @service_query = @service.send(method)
         
     | 
| 
       57 
41 
     | 
    
         
             
            end
         
     | 
| 
       58 
42 
     | 
    
         | 
| 
       59 
     | 
    
         
            -
            Then /^the result should be "([^\"]*)"$/ do |result|
         
     | 
| 
       60 
     | 
    
         
            -
              @service_result.should eq result
         
     | 
| 
       61 
     | 
    
         
            -
            end
         
     | 
| 
       62 
     | 
    
         
            -
             
     | 
| 
       63 
43 
     | 
    
         
             
            Then /^the integer result should be ([^\"]*)$/ do |result|
         
     | 
| 
       64 
44 
     | 
    
         
             
              @service_result.should eq result.to_i
         
     | 
| 
       65 
45 
     | 
    
         
             
            end
         
     | 
| 
         @@ -216,27 +196,6 @@ Then /^the result should be:$/ do |table| 
     | 
|
| 
       216 
196 
     | 
    
         
             
              table.diff!(result_table)
         
     | 
| 
       217 
197 
     | 
    
         
             
            end
         
     | 
| 
       218 
198 
     | 
    
         | 
| 
       219 
     | 
    
         
            -
            Then /^the save result should be:$/ do |table|
         
     | 
| 
       220 
     | 
    
         
            -
              # table is a Cucumber::Ast::Table
         
     | 
| 
       221 
     | 
    
         
            -
             
     | 
| 
       222 
     | 
    
         
            -
              fields = table.hashes[0].keys
         
     | 
| 
       223 
     | 
    
         
            -
             
     | 
| 
       224 
     | 
    
         
            -
              # Build an array of hashes so that we can compare tables
         
     | 
| 
       225 
     | 
    
         
            -
              results = []
         
     | 
| 
       226 
     | 
    
         
            -
             
     | 
| 
       227 
     | 
    
         
            -
              @saved_result.each do |result|
         
     | 
| 
       228 
     | 
    
         
            -
                obj_hash = Hash.new
         
     | 
| 
       229 
     | 
    
         
            -
                fields.each do |field|
         
     | 
| 
       230 
     | 
    
         
            -
                  obj_hash[field] = result.send(field)
         
     | 
| 
       231 
     | 
    
         
            -
                end
         
     | 
| 
       232 
     | 
    
         
            -
                results << obj_hash
         
     | 
| 
       233 
     | 
    
         
            -
              end
         
     | 
| 
       234 
     | 
    
         
            -
             
     | 
| 
       235 
     | 
    
         
            -
              result_table = Cucumber::Ast::Table.new(results)
         
     | 
| 
       236 
     | 
    
         
            -
             
     | 
| 
       237 
     | 
    
         
            -
              table.diff!(result_table)
         
     | 
| 
       238 
     | 
    
         
            -
            end
         
     | 
| 
       239 
     | 
    
         
            -
             
     | 
| 
       240 
199 
     | 
    
         
             
            Then /^a class named "([^\"]*)" should exist$/ do |klass_name|
         
     | 
| 
       241 
200 
     | 
    
         
             
              (Object.const_defined? klass_name).should eq true
         
     | 
| 
       242 
201 
     | 
    
         
             
            end
         
     | 
| 
         @@ -261,14 +220,6 @@ When /^I set "([^\"]*)" on the result's method "([^\"]*)" to "([^\"]*)"$/ do |pr 
     | 
|
| 
       261 
220 
     | 
    
         
             
            end
         
     | 
| 
       262 
221 
     | 
    
         | 
| 
       263 
222 
     | 
    
         
             
            # Type tests
         
     | 
| 
       264 
     | 
    
         
            -
            Then /^the "([^\"]*)" method should return a (.*)/ do |method_name, type|
         
     | 
| 
       265 
     | 
    
         
            -
              methods = method_name.split '.'
         
     | 
| 
       266 
     | 
    
         
            -
              if methods.length == 1
         
     | 
| 
       267 
     | 
    
         
            -
                @service_result.send(method_name).class.to_s.should eq type
         
     | 
| 
       268 
     | 
    
         
            -
              else
         
     | 
| 
       269 
     | 
    
         
            -
                @service_result.send(methods[0]).send(methods[1]).class.to_s.should eq type
         
     | 
| 
       270 
     | 
    
         
            -
              end
         
     | 
| 
       271 
     | 
    
         
            -
            end
         
     | 
| 
       272 
223 
     | 
    
         
             
            Then /^the "([^\"]*)" method on the object should return a (.*)/ do |method_name, type|
         
     | 
| 
       273 
224 
     | 
    
         
             
              methods = method_name.split '.'
         
     | 
| 
       274 
225 
     | 
    
         
             
              if methods.length == 1
         
     | 
| 
         @@ -284,16 +235,9 @@ end 
     | 
|
| 
       284 
235 
     | 
    
         | 
| 
       285 
236 
     | 
    
         
             
            Then /^the new query result's time "([^\"]*)" should equal the saved query result$/ do |method_name|
         
     | 
| 
       286 
237 
     | 
    
         
             
              methods = method_name.split '.'
         
     | 
| 
       287 
     | 
    
         
            -
               
     | 
| 
       288 
     | 
    
         
            -
                @service_result.send(method_name).xmlschema(3).should eq @stored_query_result.send(method_name).xmlschema(3)
         
     | 
| 
       289 
     | 
    
         
            -
              else
         
     | 
| 
       290 
     | 
    
         
            -
                @service_result.send(methods[0]).send(methods[1]).xmlschema(3).should eq @stored_query_result.send(methods[0]).send(methods[1]).xmlschema(3)
         
     | 
| 
       291 
     | 
    
         
            -
              end
         
     | 
| 
      
 238 
     | 
    
         
            +
              @service_result.send(methods[0]).send(methods[1]).xmlschema(3).should eq @stored_query_result.send(methods[0]).send(methods[1]).xmlschema(3)
         
     | 
| 
       292 
239 
     | 
    
         
             
            end
         
     | 
| 
       293 
240 
     | 
    
         | 
| 
       294 
     | 
    
         
            -
            Then /^show me the results$/ do
         
     | 
| 
       295 
     | 
    
         
            -
              puts @service_result
         
     | 
| 
       296 
     | 
    
         
            -
            end
         
     | 
| 
       297 
241 
     | 
    
         | 
| 
       298 
242 
     | 
    
         
             
            Then /^the result count should be (\d+)$/ do |expected_count|
         
     | 
| 
       299 
243 
     | 
    
         
             
              @service_result.count.should eq expected_count.to_i
         
     | 
| 
         @@ -313,4 +257,4 @@ end 
     | 
|
| 
       313 
257 
     | 
    
         | 
| 
       314 
258 
     | 
    
         
             
            When /^(.*) within a cassette named "([^"]*)"$/ do |the_step, cassette_name|
         
     | 
| 
       315 
259 
     | 
    
         
             
              VCR.use_cassette(cassette_name) { step the_step }
         
     | 
| 
       316 
     | 
    
         
            -
            end
         
     | 
| 
      
 260 
     | 
    
         
            +
            end
         
     | 
    
        data/features/support/env.rb
    CHANGED
    
    
    
        data/lib/ruby_odata.rb
    CHANGED
    
    
| 
         @@ -110,6 +110,20 @@ module OData 
     | 
|
| 
       110 
110 
     | 
    
         
             
                      end
         
     | 
| 
       111 
111 
     | 
    
         
             
                    end
         
     | 
| 
       112 
112 
     | 
    
         | 
| 
      
 113 
     | 
    
         
            +
                    props = self.class.properties
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
                    # Convert a Int64 to a string for serialization (to match Edm.Int64)
         
     | 
| 
      
 116 
     | 
    
         
            +
                    bigints = vars.find_all { |o| props[o[0]] && props[o[0]].type == "Edm.Int64" } || []
         
     | 
| 
      
 117 
     | 
    
         
            +
                    bigints.each do |i|
         
     | 
| 
      
 118 
     | 
    
         
            +
                      vars[i[0]] = i[1].to_s
         
     | 
| 
      
 119 
     | 
    
         
            +
                    end
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
                    # Convert Arrays into proper Collections
         
     | 
| 
      
 122 
     | 
    
         
            +
                    collections = vars.find_all { |o| o[1].class == Array } || []
         
     | 
| 
      
 123 
     | 
    
         
            +
                    collections.each do |c|
         
     | 
| 
      
 124 
     | 
    
         
            +
                      vars[c[0]] = { '__metadata' => { 'type' => props[c[0]].type }, 'results' => c[1] }
         
     | 
| 
      
 125 
     | 
    
         
            +
                    end
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
       113 
127 
     | 
    
         
             
                    # Convert a BigDecimal to a string for serialization (to match Edm.Decimal)
         
     | 
| 
       114 
128 
     | 
    
         
             
                    decimals = vars.find_all { |o| o[1].class == BigDecimal } || []
         
     | 
| 
       115 
129 
     | 
    
         
             
                    decimals.each do |d|
         
     | 
    
        data/lib/ruby_odata/service.rb
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module OData
         
     | 
| 
       2 
2 
     | 
    
         
             
            # The main service class, also known as a *Context*
         
     | 
| 
       3 
3 
     | 
    
         
             
            class Service
         
     | 
| 
       4 
     | 
    
         
            -
              attr_reader :classes, :class_metadata, :options, :collections, :edmx, :function_imports
         
     | 
| 
      
 4 
     | 
    
         
            +
              attr_reader :classes, :class_metadata, :options, :collections, :edmx, :function_imports, :response
         
     | 
| 
       5 
5 
     | 
    
         
             
              # Creates a new instance of the Service class
         
     | 
| 
       6 
6 
     | 
    
         
             
              #
         
     | 
| 
       7 
7 
     | 
    
         
             
              # @param [String] service_uri the root URI of the OData service
         
     | 
| 
         @@ -97,9 +97,9 @@ class Service 
     | 
|
| 
       97 
97 
     | 
    
         
             
              # Performs query operations (Read) against the server.
         
     | 
| 
       98 
98 
     | 
    
         
             
              # Typically this returns an array of record instances, except in the case of count queries
         
     | 
| 
       99 
99 
     | 
    
         
             
              def execute
         
     | 
| 
       100 
     | 
    
         
            -
                 
     | 
| 
       101 
     | 
    
         
            -
                return Integer( 
     | 
| 
       102 
     | 
    
         
            -
                handle_collection_result( 
     | 
| 
      
 100 
     | 
    
         
            +
                @response = RestClient::Resource.new(build_query_uri, @rest_options).get
         
     | 
| 
      
 101 
     | 
    
         
            +
                return Integer(@response) if @response =~ /^\d+$/
         
     | 
| 
      
 102 
     | 
    
         
            +
                handle_collection_result(@response)
         
     | 
| 
       103 
103 
     | 
    
         
             
              end
         
     | 
| 
       104 
104 
     | 
    
         | 
| 
       105 
105 
     | 
    
         
             
              # Overridden to identify methods handled by method_missing
         
     | 
| 
         @@ -176,6 +176,7 @@ class Service 
     | 
|
| 
       176 
176 
     | 
    
         
             
                @rest_options.merge!(options[:rest_options] || {})
         
     | 
| 
       177 
177 
     | 
    
         
             
                @additional_params = options[:additional_params] || {}
         
     | 
| 
       178 
178 
     | 
    
         
             
                @namespace = options[:namespace]
         
     | 
| 
      
 179 
     | 
    
         
            +
                @json_type = options[:json_type] || :json
         
     | 
| 
       179 
180 
     | 
    
         
             
              end
         
     | 
| 
       180 
181 
     | 
    
         | 
| 
       181 
182 
     | 
    
         
             
              def default_instance_vars!
         
     | 
| 
         @@ -312,7 +313,7 @@ class Service 
     | 
|
| 
       312 
313 
     | 
    
         | 
| 
       313 
314 
     | 
    
         
             
              # Handles errors from the OData service
         
     | 
| 
       314 
315 
     | 
    
         
             
              def handle_exception(e)
         
     | 
| 
       315 
     | 
    
         
            -
                raise e unless e.response
         
     | 
| 
      
 316 
     | 
    
         
            +
                raise e unless defined? e.response
         
     | 
| 
       316 
317 
     | 
    
         | 
| 
       317 
318 
     | 
    
         
             
                code = e.http_code
         
     | 
| 
       318 
319 
     | 
    
         
             
                error = Nokogiri::XML(e.response)
         
     | 
| 
         @@ -375,11 +376,7 @@ class Service 
     | 
|
| 
       375 
376 
     | 
    
         | 
| 
       376 
377 
     | 
    
         
             
                return nil if klass_name.nil?
         
     | 
| 
       377 
378 
     | 
    
         | 
| 
       378 
     | 
    
         
            -
                 
     | 
| 
       379 
     | 
    
         
            -
                # have properties that are ancestors of m:inline. Check if there is an m:inline child to determine the xpath query to use
         
     | 
| 
       380 
     | 
    
         
            -
                has_inline = entry.xpath(".//m:inline", @ds_namespaces).any?
         
     | 
| 
       381 
     | 
    
         
            -
                properties_xpath = has_inline ? ".//m:properties[not(ancestor::m:inline)]/*" : ".//m:properties/*"
         
     | 
| 
       382 
     | 
    
         
            -
                properties = entry.xpath(properties_xpath, @ds_namespaces)
         
     | 
| 
      
 379 
     | 
    
         
            +
                properties = entry.xpath("./atom:content/m:properties/*", @ds_namespaces)
         
     | 
| 
       383 
380 
     | 
    
         | 
| 
       384 
381 
     | 
    
         
             
                klass = @classes[qualify_class_name(klass_name)].new
         
     | 
| 
       385 
382 
     | 
    
         | 
| 
         @@ -390,7 +387,7 @@ class Service 
     | 
|
| 
       390 
387 
     | 
    
         
             
                # Fill properties
         
     | 
| 
       391 
388 
     | 
    
         
             
                for prop in properties
         
     | 
| 
       392 
389 
     | 
    
         
             
                  prop_name = prop.name
         
     | 
| 
       393 
     | 
    
         
            -
                  klass.send "#{prop_name}=",  
     | 
| 
      
 390 
     | 
    
         
            +
                  klass.send "#{prop_name}=", parse_value_xml(prop)
         
     | 
| 
       394 
391 
     | 
    
         
             
                end
         
     | 
| 
       395 
392 
     | 
    
         | 
| 
       396 
393 
     | 
    
         
             
                # Fill properties represented outside of the properties collection
         
     | 
| 
         @@ -407,15 +404,14 @@ class Service 
     | 
|
| 
       407 
404 
     | 
    
         
             
                inline_links = entry.xpath("./atom:link[m:inline]", @ds_namespaces)
         
     | 
| 
       408 
405 
     | 
    
         | 
| 
       409 
406 
     | 
    
         
             
                for link in inline_links
         
     | 
| 
       410 
     | 
    
         
            -
                  inline_entries = link.xpath(".//atom:entry", @ds_namespaces)
         
     | 
| 
       411 
     | 
    
         
            -
             
     | 
| 
       412 
407 
     | 
    
         
             
                  # TODO: Use the metadata's associations to determine the multiplicity instead of this "hack"
         
     | 
| 
       413 
408 
     | 
    
         
             
                  property_name = link.attributes['title'].to_s
         
     | 
| 
       414 
     | 
    
         
            -
                  if  
     | 
| 
       415 
     | 
    
         
            -
                     
     | 
| 
      
 409 
     | 
    
         
            +
                  if singular?(property_name)
         
     | 
| 
      
 410 
     | 
    
         
            +
                    inline_entry = link.xpath("./m:inline/atom:entry", @ds_namespaces).first
         
     | 
| 
      
 411 
     | 
    
         
            +
                    inline_klass = build_inline_class(klass, inline_entry, property_name)
         
     | 
| 
       416 
412 
     | 
    
         
             
                    klass.send "#{property_name}=", inline_klass
         
     | 
| 
       417 
413 
     | 
    
         
             
                  else
         
     | 
| 
       418 
     | 
    
         
            -
                    inline_classes = []
         
     | 
| 
      
 414 
     | 
    
         
            +
                    inline_classes, inline_entries = [], link.xpath("./m:inline/atom:feed/atom:entry", @ds_namespaces)
         
     | 
| 
       419 
415 
     | 
    
         
             
                    for inline_entry in inline_entries
         
     | 
| 
       420 
416 
     | 
    
         
             
                      # Build the class
         
     | 
| 
       421 
417 
     | 
    
         
             
                      inline_klass = entry_to_class(inline_entry)
         
     | 
| 
         @@ -438,7 +434,7 @@ class Service 
     | 
|
| 
       438 
434 
     | 
    
         
             
                next_links = doc.xpath('//atom:link[@rel="next"]', @ds_namespaces)
         
     | 
| 
       439 
435 
     | 
    
         
             
                @has_partial = next_links.any?
         
     | 
| 
       440 
436 
     | 
    
         
             
                if @has_partial
         
     | 
| 
       441 
     | 
    
         
            -
                  uri = Addressable::URI.parse(next_links[0]['href']) 
     | 
| 
      
 437 
     | 
    
         
            +
                  uri = Addressable::URI.parse(next_links[0]['href'])
         
     | 
| 
       442 
438 
     | 
    
         
             
                  uri.query_values = uri.query_values.merge @additional_params unless @additional_params.empty?
         
     | 
| 
       443 
439 
     | 
    
         
             
                  @next_uri = uri.to_s
         
     | 
| 
       444 
440 
     | 
    
         
             
                end
         
     | 
| 
         @@ -537,12 +533,12 @@ class Service 
     | 
|
| 
       537 
533 
     | 
    
         
             
                if operation.kind == "Add"
         
     | 
| 
       538 
534 
     | 
    
         
             
                  save_uri = build_save_uri(operation)
         
     | 
| 
       539 
535 
     | 
    
         
             
                  json_klass = operation.klass.to_json(:type => :add)
         
     | 
| 
       540 
     | 
    
         
            -
                  post_result = RestClient::Resource.new(save_uri, @rest_options).post json_klass, {:content_type =>  
     | 
| 
      
 536 
     | 
    
         
            +
                  post_result = RestClient::Resource.new(save_uri, @rest_options).post json_klass, {:content_type => @json_type}
         
     | 
| 
       541 
537 
     | 
    
         
             
                  return build_classes_from_result(post_result)
         
     | 
| 
       542 
538 
     | 
    
         
             
                elsif operation.kind == "Update"
         
     | 
| 
       543 
539 
     | 
    
         
             
                  update_uri = build_resource_uri(operation)
         
     | 
| 
       544 
540 
     | 
    
         
             
                  json_klass = operation.klass.to_json
         
     | 
| 
       545 
     | 
    
         
            -
                  update_result = RestClient::Resource.new(update_uri, @rest_options).put json_klass, {:content_type =>  
     | 
| 
      
 541 
     | 
    
         
            +
                  update_result = RestClient::Resource.new(update_uri, @rest_options).put json_klass, {:content_type => @json_type}
         
     | 
| 
       546 
542 
     | 
    
         
             
                  return (update_result.code == 204)
         
     | 
| 
       547 
543 
     | 
    
         
             
                elsif operation.kind == "Delete"
         
     | 
| 
       548 
544 
     | 
    
         
             
                  delete_uri = build_resource_uri(operation)
         
     | 
| 
         @@ -551,7 +547,7 @@ class Service 
     | 
|
| 
       551 
547 
     | 
    
         
             
                elsif operation.kind == "AddLink"
         
     | 
| 
       552 
548 
     | 
    
         
             
                  save_uri = build_add_link_uri(operation)
         
     | 
| 
       553 
549 
     | 
    
         
             
                  json_klass = operation.child_klass.to_json(:type => :link)
         
     | 
| 
       554 
     | 
    
         
            -
                  post_result = RestClient::Resource.new(save_uri, @rest_options).post json_klass, {:content_type =>  
     | 
| 
      
 550 
     | 
    
         
            +
                  post_result = RestClient::Resource.new(save_uri, @rest_options).post json_klass, {:content_type => @json_type}
         
     | 
| 
       555 
551 
     | 
    
         | 
| 
       556 
552 
     | 
    
         
             
                  # Attach the child to the parent
         
     | 
| 
       557 
553 
     | 
    
         
             
                  link_child_to_parent(operation) if (post_result.code == 204)
         
     | 
| 
         @@ -636,16 +632,45 @@ class Service 
     | 
|
| 
       636 
632 
     | 
    
         | 
| 
       637 
633 
     | 
    
         
             
              # Complex Types
         
     | 
| 
       638 
634 
     | 
    
         
             
              def complex_type_to_class(complex_type_xml)
         
     | 
| 
       639 
     | 
    
         
            -
                 
     | 
| 
       640 
     | 
    
         
            -
             
     | 
| 
      
 635 
     | 
    
         
            +
                type = Helpers.get_namespaced_attribute(complex_type_xml, 'type', 'm')
         
     | 
| 
      
 636 
     | 
    
         
            +
             
     | 
| 
      
 637 
     | 
    
         
            +
                is_collection = false
         
     | 
| 
      
 638 
     | 
    
         
            +
                # Extract the class name in case this is a Collection
         
     | 
| 
      
 639 
     | 
    
         
            +
                if type =~ /\(([^)]*)\)/m
         
     | 
| 
      
 640 
     | 
    
         
            +
                	type = $~[1]
         
     | 
| 
      
 641 
     | 
    
         
            +
                  is_collection = true
         
     | 
| 
      
 642 
     | 
    
         
            +
                  collection = []
         
     | 
| 
      
 643 
     | 
    
         
            +
                end
         
     | 
| 
       641 
644 
     | 
    
         | 
| 
       642 
     | 
    
         
            -
                 
     | 
| 
      
 645 
     | 
    
         
            +
                klass_name = qualify_class_name(type.split('.')[-1])
         
     | 
| 
      
 646 
     | 
    
         
            +
             
     | 
| 
      
 647 
     | 
    
         
            +
                if is_collection
         
     | 
| 
      
 648 
     | 
    
         
            +
                  # extract the elements from the collection
         
     | 
| 
      
 649 
     | 
    
         
            +
                  elements = complex_type_xml.xpath(".//d:element", @namespaces)
         
     | 
| 
      
 650 
     | 
    
         
            +
                  elements.each do |e|
         
     | 
| 
      
 651 
     | 
    
         
            +
                    if type.match(/^Edm/)
         
     | 
| 
      
 652 
     | 
    
         
            +
                      collection << parse_value(e.content, type)
         
     | 
| 
      
 653 
     | 
    
         
            +
                    else
         
     | 
| 
      
 654 
     | 
    
         
            +
                      element = @classes[klass_name].new
         
     | 
| 
      
 655 
     | 
    
         
            +
                      fill_complex_type_properties(e, element)
         
     | 
| 
      
 656 
     | 
    
         
            +
                      collection << element
         
     | 
| 
      
 657 
     | 
    
         
            +
                    end
         
     | 
| 
      
 658 
     | 
    
         
            +
                  end
         
     | 
| 
      
 659 
     | 
    
         
            +
                  return collection
         
     | 
| 
      
 660 
     | 
    
         
            +
                else
         
     | 
| 
      
 661 
     | 
    
         
            +
                  klass = @classes[klass_name].new
         
     | 
| 
      
 662 
     | 
    
         
            +
                  # Fill in the properties
         
     | 
| 
      
 663 
     | 
    
         
            +
                  fill_complex_type_properties(complex_type_xml, klass)
         
     | 
| 
      
 664 
     | 
    
         
            +
                  return klass
         
     | 
| 
      
 665 
     | 
    
         
            +
                end
         
     | 
| 
      
 666 
     | 
    
         
            +
              end
         
     | 
| 
      
 667 
     | 
    
         
            +
             
     | 
| 
      
 668 
     | 
    
         
            +
              # Helper method for complex_type_to_class
         
     | 
| 
      
 669 
     | 
    
         
            +
              def fill_complex_type_properties(complex_type_xml, klass)
         
     | 
| 
       643 
670 
     | 
    
         
             
                properties = complex_type_xml.xpath(".//*")
         
     | 
| 
       644 
671 
     | 
    
         
             
                properties.each do |prop|
         
     | 
| 
       645 
     | 
    
         
            -
                  klass.send "#{prop.name}=",  
     | 
| 
      
 672 
     | 
    
         
            +
                  klass.send "#{prop.name}=", parse_value_xml(prop)
         
     | 
| 
       646 
673 
     | 
    
         
             
                end
         
     | 
| 
       647 
     | 
    
         
            -
             
     | 
| 
       648 
     | 
    
         
            -
                return klass
         
     | 
| 
       649 
674 
     | 
    
         
             
              end
         
     | 
| 
       650 
675 
     | 
    
         | 
| 
       651 
676 
     | 
    
         
             
              # Field Converters
         
     | 
| 
         @@ -668,31 +693,36 @@ class Service 
     | 
|
| 
       668 
693 
     | 
    
         
             
              end
         
     | 
| 
       669 
694 
     | 
    
         | 
| 
       670 
695 
     | 
    
         
             
              # Parses a value into the proper type based on an xml property element
         
     | 
| 
       671 
     | 
    
         
            -
              def  
     | 
| 
      
 696 
     | 
    
         
            +
              def parse_value_xml(property_xml)
         
     | 
| 
       672 
697 
     | 
    
         
             
                property_type = Helpers.get_namespaced_attribute(property_xml, 'type', 'm')
         
     | 
| 
       673 
698 
     | 
    
         
             
                property_null = Helpers.get_namespaced_attribute(property_xml, 'null', 'm')
         
     | 
| 
       674 
699 
     | 
    
         | 
| 
       675 
     | 
    
         
            -
                 
     | 
| 
       676 
     | 
    
         
            -
             
     | 
| 
      
 700 
     | 
    
         
            +
                if property_type.nil? || (property_type && property_type.match(/^Edm/))
         
     | 
| 
      
 701 
     | 
    
         
            +
                  return parse_value(property_xml.content, property_type, property_null)
         
     | 
| 
      
 702 
     | 
    
         
            +
                end
         
     | 
| 
      
 703 
     | 
    
         
            +
             
     | 
| 
      
 704 
     | 
    
         
            +
                complex_type_to_class(property_xml)
         
     | 
| 
      
 705 
     | 
    
         
            +
              end
         
     | 
| 
       677 
706 
     | 
    
         | 
| 
      
 707 
     | 
    
         
            +
              def parse_value(content, property_type = nil, property_null = nil)
         
     | 
| 
       678 
708 
     | 
    
         
             
                # Handle anything marked as null
         
     | 
| 
       679 
709 
     | 
    
         
             
                return nil if !property_null.nil? && property_null == "true"
         
     | 
| 
       680 
710 
     | 
    
         | 
| 
       681 
     | 
    
         
            -
                # Handle  
     | 
| 
       682 
     | 
    
         
            -
                return  
     | 
| 
      
 711 
     | 
    
         
            +
                # Handle a nil property type, this is a string
         
     | 
| 
      
 712 
     | 
    
         
            +
                return content if property_type.nil?
         
     | 
| 
       683 
713 
     | 
    
         | 
| 
       684 
714 
     | 
    
         
             
                # Handle integers
         
     | 
| 
       685 
     | 
    
         
            -
                return  
     | 
| 
      
 715 
     | 
    
         
            +
                return content.to_i if property_type.match(/^Edm.Int/)
         
     | 
| 
       686 
716 
     | 
    
         | 
| 
       687 
717 
     | 
    
         
             
                # Handle decimals
         
     | 
| 
       688 
     | 
    
         
            -
                return  
     | 
| 
      
 718 
     | 
    
         
            +
                return content.to_d if property_type.match(/Edm.Decimal/)
         
     | 
| 
       689 
719 
     | 
    
         | 
| 
       690 
720 
     | 
    
         
             
                # Handle DateTimes
         
     | 
| 
       691 
721 
     | 
    
         
             
                # return Time.parse(property_xml.content) if property_type.match(/Edm.DateTime/)
         
     | 
| 
       692 
     | 
    
         
            -
                return parse_date( 
     | 
| 
      
 722 
     | 
    
         
            +
                return parse_date(content) if property_type.match(/Edm.DateTime/)
         
     | 
| 
       693 
723 
     | 
    
         | 
| 
       694 
724 
     | 
    
         
             
                # If we can't parse the value, just return the element's content
         
     | 
| 
       695 
     | 
    
         
            -
                 
     | 
| 
      
 725 
     | 
    
         
            +
                content
         
     | 
| 
       696 
726 
     | 
    
         
             
              end
         
     | 
| 
       697 
727 
     | 
    
         | 
| 
       698 
728 
     | 
    
         
             
              # Parses a value into the proper type based on a specified return type
         
     |