abiquo-etk 0.6.0 → 0.6.1
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/Rakefile +0 -1
- data/VERSION +1 -1
- data/vendor/abiquo-0.1.2/.bundle/config +2 -0
- data/vendor/abiquo-0.1.2/Gemfile +9 -0
- data/vendor/abiquo-0.1.2/LICENSE +20 -0
- data/vendor/abiquo-0.1.2/README +39 -0
- data/vendor/abiquo-0.1.2/Rakefile +88 -0
- data/vendor/abiquo-0.1.2/abiquo.gemspec +43 -0
- data/vendor/abiquo-0.1.2/examples/add_hypervisor.rb +24 -0
- data/vendor/abiquo-0.1.2/examples/create_dc_and_hv.rb +38 -0
- data/vendor/abiquo-0.1.2/examples/hypervisor_resource.rb +16 -0
- data/vendor/abiquo-0.1.2/examples/rack_resource.rb +38 -0
- data/vendor/abiquo-0.1.2/lib/abiquo.rb +210 -0
- data/vendor/abiquo-0.1.2/lib/active_support/inflections.rb +170 -0
- data/vendor/abiquo-0.1.2/lib/active_support/inflector.rb +411 -0
- data/vendor/abiquo-0.1.2/lib/core_ext.rb +381 -0
- data/vendor/abiquo-0.1.2/lib/to_xml.rb +22 -0
- data/vendor/abiquo-0.1.2/spec/acceptance/create_resource_spec.rb +43 -0
- data/vendor/abiquo-0.1.2/spec/acceptance/delete_resource_spec.rb +27 -0
- data/vendor/abiquo-0.1.2/spec/acceptance/fetch_resource_collections_spec.rb +55 -0
- data/vendor/abiquo-0.1.2/spec/acceptance/fetch_single_resources_spec.rb +47 -0
- data/vendor/abiquo-0.1.2/spec/acceptance/from_xml_spec.rb +15 -0
- data/vendor/abiquo-0.1.2/spec/acceptance/navigate_linked_resources_spec.rb +61 -0
- data/vendor/abiquo-0.1.2/spec/acceptance/update_resource_spec.rb +26 -0
- data/vendor/abiquo-0.1.2/spec/spec_helper.rb +32 -0
- data/vendor/abiquo-0.1.2/spec/unit/to_xml_spec.rb +56 -0
- metadata +29 -21
data/Rakefile
CHANGED
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.6.
|
|
1
|
+
0.6.1
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2010 Abiquo Holdings
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
=Abiquo API Ruby client
|
|
2
|
+
|
|
3
|
+
Rest client to work with the Abiquo's API.
|
|
4
|
+
|
|
5
|
+
==Installation
|
|
6
|
+
|
|
7
|
+
gem install abiquo
|
|
8
|
+
|
|
9
|
+
==Usage
|
|
10
|
+
|
|
11
|
+
The first version of the api just uses basic authentication, so we need to create an instance with our credentials:
|
|
12
|
+
|
|
13
|
+
auth = Abiquo::BasicAuth.new('Abiquo', 'username', 'password')
|
|
14
|
+
|
|
15
|
+
The entry point for the Abiquo's API is an atom document service:
|
|
16
|
+
|
|
17
|
+
api = Abiquo::Resource('http://abiquo.example.com/api', auth)
|
|
18
|
+
|
|
19
|
+
from this point we can access to every resource exposed by the api calling nested methods:
|
|
20
|
+
|
|
21
|
+
datacenters = api.datacenters
|
|
22
|
+
racks = api.datacenters.first.racks
|
|
23
|
+
|
|
24
|
+
or get the values of their elements:
|
|
25
|
+
|
|
26
|
+
datacenter = api.datacenters.first
|
|
27
|
+
datacenter.name # => The name of the datacenter
|
|
28
|
+
|
|
29
|
+
You can find further example into the specs:
|
|
30
|
+
|
|
31
|
+
http://github.com/abiquo/api_ruby_client/tree/master/spec/acceptance
|
|
32
|
+
|
|
33
|
+
Further documentation of the API can be found in our wiki:
|
|
34
|
+
|
|
35
|
+
http://abicloud.org/display/ABI16/Abiquo's+API
|
|
36
|
+
|
|
37
|
+
==Copyright
|
|
38
|
+
|
|
39
|
+
Copyright (c) 2010 Abiquo Holdings. See LICENSE for details.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
require "rubygems"
|
|
2
|
+
require "rake/gempackagetask"
|
|
3
|
+
require "rake/rdoctask"
|
|
4
|
+
|
|
5
|
+
require "spec"
|
|
6
|
+
require "spec/rake/spectask"
|
|
7
|
+
|
|
8
|
+
desc "Run acceptance specs"
|
|
9
|
+
Spec::Rake::SpecTask.new("spec:acceptance") do |t|
|
|
10
|
+
t.spec_opts = "--format specdoc --colour".split
|
|
11
|
+
t.spec_files = ["spec/acceptance"]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
desc "Run unit specs"
|
|
15
|
+
Spec::Rake::SpecTask.new("spec:unit") do |t|
|
|
16
|
+
t.spec_files = ["spec/unit"]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
desc "Run all specs"
|
|
20
|
+
task :spec => ["spec:unit", "spec:acceptance"]
|
|
21
|
+
|
|
22
|
+
task :default => ["spec"]
|
|
23
|
+
|
|
24
|
+
# This builds the actual gem. For details of what all these options
|
|
25
|
+
# mean, and other ones you can add, check the documentation here:
|
|
26
|
+
#
|
|
27
|
+
# http://rubygems.org/read/chapter/20
|
|
28
|
+
#
|
|
29
|
+
spec = Gem::Specification.new do |s|
|
|
30
|
+
|
|
31
|
+
# Change these as appropriate
|
|
32
|
+
s.name = "abiquo"
|
|
33
|
+
s.version = "0.1.2"
|
|
34
|
+
s.summary = "Abiquo API client"
|
|
35
|
+
s.author = "Abiquo"
|
|
36
|
+
s.email = "support@abiquo.com"
|
|
37
|
+
s.homepage = "http://github.com/abiquo/api_ruby_client"
|
|
38
|
+
|
|
39
|
+
s.has_rdoc = true
|
|
40
|
+
# You should probably have a README of some kind. Change the filename
|
|
41
|
+
# as appropriate
|
|
42
|
+
s.extra_rdoc_files = %w(README)
|
|
43
|
+
s.rdoc_options = %w(--main README)
|
|
44
|
+
|
|
45
|
+
# Add any extra files to include in the gem (like your README)
|
|
46
|
+
s.files = %w() + Dir.glob("{lib/**/*}")
|
|
47
|
+
s.require_paths = ["lib"]
|
|
48
|
+
|
|
49
|
+
# If you want to depend on other gems, add them here, along with any
|
|
50
|
+
# relevant versions
|
|
51
|
+
s.add_dependency("resourceful")
|
|
52
|
+
s.add_dependency("nokogiri")
|
|
53
|
+
|
|
54
|
+
# If your tests use any gems, include them here
|
|
55
|
+
s.add_development_dependency("steak")
|
|
56
|
+
s.add_development_dependency("webmock")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# This task actually builds the gem. We also regenerate a static
|
|
60
|
+
# .gemspec file, which is useful if something (i.e. GitHub) will
|
|
61
|
+
# be automatically building a gem for this project. If you're not
|
|
62
|
+
# using GitHub, edit as appropriate.
|
|
63
|
+
#
|
|
64
|
+
# To publish your gem online, install the 'gemcutter' gem; Read more
|
|
65
|
+
# about that here: http://gemcutter.org/pages/gem_docs
|
|
66
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
|
67
|
+
pkg.gem_spec = spec
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
desc "Build the gemspec file #{spec.name}.gemspec"
|
|
71
|
+
task :gemspec do
|
|
72
|
+
file = File.dirname(__FILE__) + "/#{spec.name}.gemspec"
|
|
73
|
+
File.open(file, "w") {|f| f << spec.to_ruby }
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
task :package => :gemspec
|
|
77
|
+
|
|
78
|
+
# Generate documentation
|
|
79
|
+
Rake::RDocTask.new do |rd|
|
|
80
|
+
|
|
81
|
+
rd.rdoc_files.include("lib/**/*.rb", "README.rdoc")
|
|
82
|
+
rd.rdoc_dir = "rdoc"
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
desc 'Clear out RDoc and generated packages'
|
|
86
|
+
task :clean => [:clobber_rdoc, :clobber_package] do
|
|
87
|
+
rm "#{spec.name}.gemspec"
|
|
88
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |s|
|
|
4
|
+
s.name = %q{abiquo}
|
|
5
|
+
s.version = "0.1.0"
|
|
6
|
+
|
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
8
|
+
s.authors = ["Abiquo"]
|
|
9
|
+
s.date = %q{2010-07-28}
|
|
10
|
+
s.email = %q{support@abiquo.com}
|
|
11
|
+
s.extra_rdoc_files = ["README.rdoc"]
|
|
12
|
+
s.files = ["lib/to_xml.rb", "lib/core_ext.rb", "lib/abiquo.rb", "README.rdoc"]
|
|
13
|
+
s.homepage = %q{http://wiki.github.com/abiquo/abiquo/}
|
|
14
|
+
s.rdoc_options = ["--main", "README.rdoc"]
|
|
15
|
+
s.require_paths = ["lib"]
|
|
16
|
+
s.rubygems_version = %q{1.3.6}
|
|
17
|
+
s.summary = %q{Abiquo API client}
|
|
18
|
+
|
|
19
|
+
if s.respond_to? :specification_version then
|
|
20
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
|
21
|
+
s.specification_version = 3
|
|
22
|
+
|
|
23
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
|
24
|
+
s.add_runtime_dependency(%q<resourceful>, [">= 0"])
|
|
25
|
+
s.add_runtime_dependency(%q<nokogiri>, [">= 0"])
|
|
26
|
+
s.add_runtime_dependency(%q<activesupport>, [">= 0"])
|
|
27
|
+
s.add_development_dependency(%q<steak>, [">= 0"])
|
|
28
|
+
s.add_development_dependency(%q<webmock>, [">= 0"])
|
|
29
|
+
else
|
|
30
|
+
s.add_dependency(%q<resourceful>, [">= 0"])
|
|
31
|
+
s.add_dependency(%q<nokogiri>, [">= 0"])
|
|
32
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
|
33
|
+
s.add_dependency(%q<steak>, [">= 0"])
|
|
34
|
+
s.add_dependency(%q<webmock>, [">= 0"])
|
|
35
|
+
end
|
|
36
|
+
else
|
|
37
|
+
s.add_dependency(%q<resourceful>, [">= 0"])
|
|
38
|
+
s.add_dependency(%q<nokogiri>, [">= 0"])
|
|
39
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
|
40
|
+
s.add_dependency(%q<steak>, [">= 0"])
|
|
41
|
+
s.add_dependency(%q<webmock>, [">= 0"])
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
gem 'activesupport', '2.3.8'
|
|
3
|
+
require 'abiquo'
|
|
4
|
+
require 'pp'
|
|
5
|
+
|
|
6
|
+
auth = Abiquo::BasicAuth.new('Abiquo', 'admin', 'xabiquo')
|
|
7
|
+
api = Abiquo::Resource('http://as-testing:8080/api', auth)
|
|
8
|
+
|
|
9
|
+
#
|
|
10
|
+
# Create a new Rack
|
|
11
|
+
#
|
|
12
|
+
dc = api.datacenters.first
|
|
13
|
+
|
|
14
|
+
# Create the rack
|
|
15
|
+
rack = dc.racks.create :name => 'myrack01'
|
|
16
|
+
|
|
17
|
+
#
|
|
18
|
+
# This is weird
|
|
19
|
+
#
|
|
20
|
+
# Create the machine
|
|
21
|
+
machine = rack.machines.create :name => 'fooxen', :cpu => '2', :description => 'foo', :hd => '100000', :ram => '1024', :virtualSwitch => 'eth2', :state => 'STOPPED'
|
|
22
|
+
|
|
23
|
+
# Create the HV
|
|
24
|
+
hv = machine.hypervisor.create :type => 'XEN_3', :ip => '10.0.0.1', :port => '8889', :ipService => '10.0.0.1'
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'abiquo'
|
|
3
|
+
require 'pp'
|
|
4
|
+
|
|
5
|
+
auth = Abiquo::BasicAuth.new('Abiquo', 'admin', 'xabiquo')
|
|
6
|
+
api = Abiquo::Resource('http://10.60.1.65/api', auth)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
#
|
|
10
|
+
# Create a DataCenter
|
|
11
|
+
#
|
|
12
|
+
#puts "Creating DC1 in BCN..."
|
|
13
|
+
new_datacenter = api.datacenters.create :name => 'DC1', :location => 'BCN'
|
|
14
|
+
|
|
15
|
+
#
|
|
16
|
+
# Create Remote Services
|
|
17
|
+
#
|
|
18
|
+
new_datacenter.remoteServices.create :type => 'VIRTUAL_FACTORY', :uri => 'http://localhost:8080/virtualfactory'
|
|
19
|
+
new_datacenter.remoteServices.create :type => 'STORAGE_SYSTEM_MONITOR', :uri => 'http://localhost:8080/ssm'
|
|
20
|
+
new_datacenter.remoteServices.create :type => 'VIRTUAL_SYSTEM_MONITOR', :uri => 'http://localhost:8080/vsm'
|
|
21
|
+
new_datacenter.remoteServices.create :type => 'NODE_COLLECTOR', :uri => 'http://localhost:8080/nodecollector'
|
|
22
|
+
new_datacenter.remoteServices.create :type => 'APPLIANCE_MANAGER', :uri => 'http://localhost:8080/am'
|
|
23
|
+
new_datacenter.remoteServices.create :type => 'DHCP_SERVICE', :uri => 'http://localhost:7911'
|
|
24
|
+
new_datacenter.remoteServices.create :type => 'BPM_SERVICE', :uri => 'http://localhost:7911'
|
|
25
|
+
|
|
26
|
+
#
|
|
27
|
+
# Create a new Rack
|
|
28
|
+
#
|
|
29
|
+
puts "Creating rack 'myrack01'..."
|
|
30
|
+
new_datacenter.racks.create :name => 'myrack01'
|
|
31
|
+
|
|
32
|
+
#
|
|
33
|
+
# Iterate over all the racks and print the rack name
|
|
34
|
+
#
|
|
35
|
+
puts "Listing racks.."
|
|
36
|
+
new_datacenter.racks.each do |rack|
|
|
37
|
+
pp rack.name
|
|
38
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'abiquo'
|
|
3
|
+
require 'pp'
|
|
4
|
+
|
|
5
|
+
auth = Abiquo::BasicAuth.new('Abiquo', 'admin', 'admin')
|
|
6
|
+
api = Abiquo::Resource('http://as-testing.bcn.abiquo.com:8080/api', auth)
|
|
7
|
+
|
|
8
|
+
#
|
|
9
|
+
# Iterate over all the racks and print the rack name and the hypervisors underneath
|
|
10
|
+
#
|
|
11
|
+
api.datacenters.first.racks.each do |rack|
|
|
12
|
+
puts "- RACK [#{rack.name}]"
|
|
13
|
+
rack.machines.each do |m|
|
|
14
|
+
puts "---" + m.name
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'abiquo'
|
|
3
|
+
require 'pp'
|
|
4
|
+
|
|
5
|
+
auth = Abiquo::BasicAuth.new('Abiquo', 'admin', 'admin')
|
|
6
|
+
api = Abiquo::Resource('http://as-testing.bcn.abiquo.com:8080/api', auth)
|
|
7
|
+
|
|
8
|
+
#
|
|
9
|
+
# Create a new Rack
|
|
10
|
+
#
|
|
11
|
+
puts "Creating rack 'myrack01'..."
|
|
12
|
+
api.datacenters.first.racks.create :name => 'myrack01'
|
|
13
|
+
|
|
14
|
+
#
|
|
15
|
+
# Iterate over all the racks and print the rack name
|
|
16
|
+
#
|
|
17
|
+
puts "Listing racks.."
|
|
18
|
+
api.datacenters.first.racks.each do |rack|
|
|
19
|
+
pp rack.name
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
#
|
|
23
|
+
# Iterate over all the racks and print the rack name
|
|
24
|
+
#
|
|
25
|
+
puts "Listing racks..."
|
|
26
|
+
api.datacenters.first.racks.each do |rack|
|
|
27
|
+
pp rack.name
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
#
|
|
31
|
+
# Delete the rack myrack01
|
|
32
|
+
#
|
|
33
|
+
# NOT SUPPORTED IN ABIQUO1.6
|
|
34
|
+
#
|
|
35
|
+
#puts "Deleting rack 'myrack01'..."
|
|
36
|
+
#api.datacenters.first.racks.each do |r|
|
|
37
|
+
# r.delete if r.name == 'myrack01'
|
|
38
|
+
#end
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
require 'resourceful'
|
|
2
|
+
require 'nokogiri'
|
|
3
|
+
require File.expand_path('../active_support/inflections', __FILE__)
|
|
4
|
+
require File.expand_path('../core_ext', __FILE__)
|
|
5
|
+
require File.expand_path('../to_xml', __FILE__)
|
|
6
|
+
require 'uri'
|
|
7
|
+
|
|
8
|
+
module Abiquo
|
|
9
|
+
|
|
10
|
+
class NotAllowed < RuntimeError
|
|
11
|
+
def initialize(method, url)
|
|
12
|
+
@method = method
|
|
13
|
+
@url = url
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def message
|
|
17
|
+
"Method #{@method} not allowed for #{@url}"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class BasicAuth < Resourceful::BasicAuthenticator
|
|
22
|
+
def can_handle?(request); true; end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
module HttpAccessor
|
|
26
|
+
|
|
27
|
+
def xml
|
|
28
|
+
@xml ||= begin
|
|
29
|
+
response = http.resource(url_with_params).get
|
|
30
|
+
doc = Nokogiri.parse(response.body)
|
|
31
|
+
# HACK: collections have link and totalSize entities we
|
|
32
|
+
# don't want here
|
|
33
|
+
if not doc.search('/*/totalSize').empty?
|
|
34
|
+
doc.search('/*/totalSize | /*/link').each do |node|
|
|
35
|
+
node.remove
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
doc.root
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def url_with_params
|
|
45
|
+
@options[:expand] = @options[:expand].join(",") if @options[:expand].is_a?(Array)
|
|
46
|
+
params = @options.map { |k, v| "#{k}=#{v}" }.join("&")
|
|
47
|
+
params = "?#{params}" unless params.empty?
|
|
48
|
+
@url + params
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def http
|
|
52
|
+
Resourceful::HttpAccessor.new(:authenticator => @auth)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def rest_options
|
|
56
|
+
@rest_options ||= begin
|
|
57
|
+
response = http.resource(@url).options
|
|
58
|
+
response.header['Allow'].map {|m| m.to_sym }
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
class SingleResource
|
|
65
|
+
|
|
66
|
+
include HttpAccessor
|
|
67
|
+
|
|
68
|
+
undef id
|
|
69
|
+
|
|
70
|
+
def initialize(url, auth, xml = nil, options = {})
|
|
71
|
+
@url = url
|
|
72
|
+
@auth = auth
|
|
73
|
+
@xml = xml
|
|
74
|
+
@options = options
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def update(attrs = {})
|
|
78
|
+
raise Abiquo::NotAllowed.new(:PUT, url) unless rest_options.include?(:PUT)
|
|
79
|
+
response = http.resource(url).put(attrs.to_xml(:root => object_type), :content_type => "application/xml")
|
|
80
|
+
@xml = Nokogiri.parse(response.body).root
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def delete
|
|
84
|
+
raise Abiquo::NotAllowed.new(:DELETE, url) unless rest_options.include?(:DELETE)
|
|
85
|
+
http.resource(url).delete
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def url
|
|
89
|
+
@url ||= xml.at_xpath("./link[@rel='edit']").try(:[], "href")
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
delegate :to_xml, :to => :xml
|
|
93
|
+
alias_method :inspect, :to_xml
|
|
94
|
+
|
|
95
|
+
private
|
|
96
|
+
|
|
97
|
+
def object_type
|
|
98
|
+
@object_type ||= URI.parse(url).path.split("/")[-2].singularize
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def method_missing(meth, *args, &blk)
|
|
102
|
+
attribute = xml.at_xpath("./*[name()='#{meth}' or name()='#{attribute_name(meth)}']")
|
|
103
|
+
return node_text(attribute) if attribute
|
|
104
|
+
|
|
105
|
+
link = xml.at_xpath("./link[@rel='#{meth}' or @rel='#{attribute_name(meth)}']")
|
|
106
|
+
return Resource.new(link["href"], @auth, link.at_xpath("./*"), *args) if link
|
|
107
|
+
|
|
108
|
+
if xml.namespaces.has_key?('xmlns:ns2')
|
|
109
|
+
@xml = Nokogiri.parse(xml.to_s.downcase).root
|
|
110
|
+
link = xml.at_xpath("//ns2:collection/xmlns:title[. = '#{meth}']").try(:parent)
|
|
111
|
+
return Resource.new(link['href'], @auth, nil, *args) if link
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
super
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def node_text(node)
|
|
118
|
+
node.text
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def attribute_name(attribute)
|
|
122
|
+
attribute.to_s.gsub('_', '-')
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
class ResourceCollection
|
|
128
|
+
|
|
129
|
+
include HttpAccessor
|
|
130
|
+
|
|
131
|
+
delegate :inspect, :to => :resources
|
|
132
|
+
|
|
133
|
+
def initialize(url, auth, xml = nil, options = {})
|
|
134
|
+
@url = url
|
|
135
|
+
@auth = auth
|
|
136
|
+
@xml = xml if options.empty?
|
|
137
|
+
@options = options
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def create(attrs = {})
|
|
141
|
+
raise Abiquo::NotAllowed.new(:POST, url) unless rest_options.include?(:POST)
|
|
142
|
+
response = http.resource(url_with_params).post(attrs.to_xml(:root => object_type, :convert_links => true), :content_type => "application/xml")
|
|
143
|
+
doc = Nokogiri.parse(response.body)
|
|
144
|
+
Resource.new(nil, @auth, doc.root)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
private
|
|
148
|
+
|
|
149
|
+
def object_type
|
|
150
|
+
@object_type ||= URI.parse(@url).path.split("/").last.singularize
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def resources
|
|
154
|
+
@resources ||= xml.xpath("./*").map { |subnode| Resource.new(subnode.at_xpath("./link[@rel='edit']").try(:[], "href"), @auth, subnode, @options) }
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def method_missing(meth, *args, &blk)
|
|
158
|
+
resources.send(meth, *args, &blk)
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
class Resource
|
|
163
|
+
|
|
164
|
+
include HttpAccessor
|
|
165
|
+
|
|
166
|
+
undef id
|
|
167
|
+
undef type
|
|
168
|
+
|
|
169
|
+
delegate :inspect, :to => :get!
|
|
170
|
+
|
|
171
|
+
def self.from_xml(xml, auth = nil)
|
|
172
|
+
doc = Nokogiri.parse(xml)
|
|
173
|
+
new(nil, auth, doc.root)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def initialize(url, auth, xml = nil, options = {})
|
|
177
|
+
@url = url
|
|
178
|
+
@auth = auth
|
|
179
|
+
@xml = xml
|
|
180
|
+
@options = options
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def method_missing(meth, *args, &blk)
|
|
184
|
+
@resource_object ||= resource_class(meth).new(@url, @auth, @xml, @options)
|
|
185
|
+
@resource_object.send(meth, *args, &blk)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def resource_class(meth)
|
|
189
|
+
@resource_class ||= if (Array.instance_methods + ["create"] - ["delete", "id"]).include?(meth.to_s)
|
|
190
|
+
ResourceCollection
|
|
191
|
+
else
|
|
192
|
+
SingleResource
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def get!
|
|
197
|
+
klass = SingleResource
|
|
198
|
+
if (!xml.children.empty? && xml.name.singularize == xml.children.first.name)
|
|
199
|
+
klass = ResourceCollection
|
|
200
|
+
end
|
|
201
|
+
@resource_object = klass.new(@url, @auth, @xml, @options)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def self.Resource(url, auth, params = {})
|
|
207
|
+
Resource.new(url, auth, nil, params)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
end
|