restfully 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1,6 @@
1
+ 0.4.0
2
+ * removed 'root_path' option: 'base_uri' must point to the starting resource;
3
+ * objects can now be pretty printed using 'pp object';
4
+ * Restfully::Collection now include the Enumerable module;
5
+ * Restfully::Collection inherits from Restfully::Resource;
6
+ * 'object.uid' is no longer valid. Use 'object["uid"]' instead;
data/README.rdoc CHANGED
@@ -10,105 +10,95 @@ Alpha work.
10
10
  == Usage
11
11
  === Command line
12
12
  $ export RUBYOPT="-rubygems"
13
- $ restfully base_uri [root_path] [-u username] [-p password]
13
+ $ restfully base_uri [-u username] [-p password]
14
14
 
15
15
  e.g., for the Grid5000 API:
16
- $ restfully https://api.grid5000.fr/sid /grid5000 -u username -p password
17
-
18
- If the connection was successful, you should get a prompt. Call the +root+ function to see what are the available resources. <tt>@property</tt> means that you can call the +property+ method on the object. Other properties are available via the <tt>[]</tt> function.
19
- e.g.:
20
- irb(main):005:0> root
21
- => #<Restfully::Resource:0x8848de
22
- ------------ META ------------
23
- @uri: #<URI::Generic:0x11091a8 URL:/grid5000>
24
- @uid: "grid5000"
25
- @type: "grid"
26
- @environments: Restfully::Collection
27
- @sites: Restfully::Collection
28
- @version: Restfully::Resource
29
- @versions: Restfully::Collection
30
- ------------ PROPERTIES ------------
31
- "version" => "4fe96b25d2cbfee16abe5a4fb999c82dbafc2ee8">
32
-
33
- irb(main):006:0> root.uri
34
- => #<URI::Generic:0x11091a8 URL:/grid5000>
35
-
36
- irb(main):007:0> root.sites
37
- => #<Restfully::Collection:0x881f6c
38
- ------------ META ------------
39
- @uri: "/grid5000/sites"
40
- @offset: 0
41
- @total: 9
42
- @version: Restfully::Resource
43
- @versions: Restfully::Collection
44
- ------------ PROPERTIES ------------
45
- "version" => "4fe96b25d2cbfee16abe5a4fb999c82dbafc2ee8"
46
- ------------ ITEMS ------------
47
- Restfully::Resource
48
- Restfully::Resource
49
- Restfully::Resource
50
- Restfully::Resource
51
- Restfully::Resource
52
- Restfully::Resource
53
- Restfully::Resource
54
- Restfully::Resource
55
- Restfully::Resource>
56
-
57
- irb(main):008:0> root.sites.by_uid('rennes').clusters.by_uid('paradent').nodes.by_uid('paradent-1').metrics.by_uid('mem_free', 'cpu_idle', 'bytes_in')
58
- => [#<Restfully::Resource:0x4259a
59
- ------------ META ------------
60
- @uri: "/grid5000/sites/rennes/clusters/paradent/nodes/paradent-1/metrics/mem_free"
61
- @uid: "mem_free"
62
- @type: "metric"
63
- @parent: Restfully::Resource
64
- @timeseries: Restfully::Resource
65
- ------------ PROPERTIES ------------
66
- "last_update" => -901639018
67
- "step" => 15
68
- "timeseries" => [{"xff"=>0.5, "cf"=>"AVERAGE", "rows"=>244, "pdp_per_row"=>1}, {"xff"=>0.5, "cf"=>"AVERAGE", "rows"=>244, "pdp_per_row"=>24}, {"xff"=>0.5, "cf"=>"AVERAGE", "rows"=>244, "pdp_per_row"=>168}, {"xff"=>0.5, "cf"=>"AVERAGE", "rows"=>244, "pdp_per_row"=>672}, {"xff"=>0.5, "cf"=>"AVERAGE", "rows"=>374, "pdp_per_row"=>5760}]>, #<Restfully::Resource:0x12444
69
- ------------ META ------------
70
- @uri: "/grid5000/sites/rennes/clusters/paradent/nodes/paradent-1/metrics/cpu_idle"
71
- @uid: "cpu_idle"
72
- @type: "metric"
73
- @parent: Restfully::Resource
74
- @timeseries: Restfully::Resource
75
- ------------ PROPERTIES ------------
76
- "last_update" => -901639018
77
- "step" => 15
78
- "timeseries" => [{"xff"=>0.5, "cf"=>"AVERAGE", "rows"=>244, "pdp_per_row"=>1}, {"xff"=>0.5, "cf"=>"AVERAGE", "rows"=>244, "pdp_per_row"=>24}, {"xff"=>0.5, "cf"=>"AVERAGE", "rows"=>244, "pdp_per_row"=>168}, {"xff"=>0.5, "cf"=>"AVERAGE", "rows"=>244, "pdp_per_row"=>672}, {"xff"=>0.5, "cf"=>"AVERAGE", "rows"=>374, "pdp_per_row"=>5760}]>, #<Restfully::Resource:0xe4c870
79
- ------------ META ------------
80
- @uri: "/grid5000/sites/rennes/clusters/paradent/nodes/paradent-1/metrics/bytes_in"
81
- @uid: "bytes_in"
82
- @type: "metric"
83
- @parent: Restfully::Resource
84
- @timeseries: Restfully::Resource
85
- ------------ PROPERTIES ------------
86
- "last_update" => -901639018
87
- "step" => 15
88
- "timeseries" => [{"xff"=>0.5, "cf"=>"AVERAGE", "rows"=>244, "pdp_per_row"=>1}, {"xff"=>0.5, "cf"=>"AVERAGE", "rows"=>244, "pdp_per_row"=>24}, {"xff"=>0.5, "cf"=>"AVERAGE", "rows"=>244, "pdp_per_row"=>168}, {"xff"=>0.5, "cf"=>"AVERAGE", "rows"=>244, "pdp_per_row"=>672}, {"xff"=>0.5, "cf"=>"AVERAGE", "rows"=>374, "pdp_per_row"=>5760}]>]
89
-
90
- irb(main):009:0> root.version
91
- => #<Restfully::Resource:0x8facf0
92
- ------------ META ------------
93
- @uri: "/grid5000/versions/ee1f8111c8835496a9e4a6f7c9491c0238ee9827"
94
- @uid: "ee1f8111c8835496a9e4a6f7c9491c0238ee9827"
95
- @type: "version"
96
- @parent: Restfully::Resource
97
- ------------ PROPERTIES ------------
98
- "author" => "Cyril Constantin <>"
99
- "date" => "Fri, 11 Sep 2009 14:32:48 GMT"
100
- "message" => "[environments] update of environments on sites">
101
-
102
- You may also prefer to use a configuration file to avoid entering the command line options:
16
+ $ restfully https://api.grid5000.fr/sid/grid5000 -u username -p password
17
+
18
+ If the connection was successful, you should get a prompt. You may enter
19
+ irb(main):001:0> pp root
20
+
21
+ to get back a pretty-printed output of the root resource:
22
+ #<Restfully::Resource:0x91f08c
23
+ @uri=#<URI::HTTP:0x123e30c URL:http://api.local/sid/grid5000>
24
+ LINKS
25
+ @environments=#<Restfully::Collection:0x917666>,
26
+ @sites=#<Restfully::Collection:0x9170d0>,
27
+ @version=#<Restfully::Resource:0x91852a>,
28
+ @versions=#<Restfully::Collection:0x917e68>
29
+ PROPERTIES
30
+ "uid"=>"grid5000",
31
+ "type"=>"grid",
32
+ "version"=>"4fe96b25d2cbfee16abe5a4fb999c82dbafc2ee8">
33
+
34
+ You can see the LINKS and PROPERTIES headers that respectively indicate what links you can follow from there (by calling +root.link_name+) and what properties are available (by calling +root[property_name]+).
35
+
36
+ Let's say you want to access the collection of +sites+, you would enter:
37
+ irb(main):002:0> pp root.sites
38
+
39
+ and get back:
40
+ #<Restfully::Collection:0x9170d0
41
+ @uri=#<URI::HTTP:0x122e128 URL:http://api.local/sid/grid5000/sites>
42
+ LINKS
43
+ @version=#<Restfully::Resource:0x8f553e>,
44
+ @versions=#<Restfully::Collection:0x8f52be>
45
+ PROPERTIES
46
+ "total"=>9,
47
+ "version"=>"4fe96b25d2cbfee16abe5a4fb999c82dbafc2ee8",
48
+ "offset"=>0
49
+ ITEMS (0..9)/9
50
+ #<Restfully::Resource:0x9058bc uid="bordeaux">,
51
+ #<Restfully::Resource:0x903d0a uid="grenoble">,
52
+ #<Restfully::Resource:0x901cc6 uid="lille">,
53
+ #<Restfully::Resource:0x8fff0c uid="lyon">,
54
+ #<Restfully::Resource:0x8fe288 uid="nancy">,
55
+ #<Restfully::Resource:0x8fc4a6 uid="orsay">,
56
+ #<Restfully::Resource:0x8fa782 uid="rennes">,
57
+ #<Restfully::Resource:0x8f8bb2 uid="sophia">,
58
+ #<Restfully::Resource:0x8f6c9a uid="toulouse">>
59
+
60
+ A Restfully::Collection is a special kind of Resource, which includes the Enumerable module, which means you can call all of its methods on the Restfully::Collection object. For example:
61
+ irb(main):003:0> pp root.sites.find{|s| s['uid'] == 'rennes'}
62
+ #<Restfully::Resource:0x8fa782
63
+ @uri=#<URI::HTTP:0x11f4e64 URL:http://api.local/sid/grid5000/sites/rennes>
64
+ LINKS
65
+ @environments=#<Restfully::Collection:0x8f9ab2>,
66
+ @parent=#<Restfully::Resource:0x8f981e>,
67
+ @deployments=#<Restfully::Collection:0x8f935a>,
68
+ @clusters=#<Restfully::Collection:0x8f9d46>,
69
+ @version=#<Restfully::Resource:0x8fa354>,
70
+ @versions=#<Restfully::Collection:0x8fa0b6>,
71
+ @status=#<Restfully::Collection:0x8f95ee>
72
+ PROPERTIES
73
+ "name"=>"Rennes",
74
+ "latitude"=>48.1,
75
+ "location"=>"Rennes, France",
76
+ "security_contact"=>"rennes-staff@lists.grid5000.fr",
77
+ "uid"=>"rennes",
78
+ "type"=>"site",
79
+ "user_support_contact"=>"rennes-staff@lists.grid5000.fr",
80
+ "version"=>"4fe96b25d2cbfee16abe5a4fb999c82dbafc2ee8",
81
+ "description"=>"",
82
+ "longitude"=>-1.6667,
83
+ "compilation_server"=>false,
84
+ "email_contact"=>"rennes-staff@lists.grid5000.fr",
85
+ "web"=>"http://www.irisa.fr",
86
+ "sys_admin_contact"=>"rennes-staff@lists.grid5000.fr">
87
+
88
+ or:
89
+ irb(main):006:0> root.sites.map{|s| s['uid']}.grep(/re/)
90
+ => ["grenoble", "rennes"]
91
+
92
+
93
+ To enter the command-line options, you may prefer to use a configuration file to avoid re-entering the options every time you use the client:
103
94
  $ echo '
104
- base_uri: https://api.grid5000.fr/sid
105
- root_path: /grid5000
95
+ base_uri: https://api.grid5000.fr/sid/grid5000
106
96
  username: MYLOGIN
107
97
  password: MYPASSWORD
108
- ' > ~/somewhere/api.grid5000.fr.yml
98
+ ' > ~/.restfully/api.grid5000.fr.yml && chmod 600 ~/.restfully/api.grid5000.fr.yml
109
99
 
110
100
  And then:
111
- $ restfully -c ~/somewhere/api.grid5000.fr.yml
101
+ $ restfully -c ~/.restfully/api.grid5000.fr.yml
112
102
 
113
103
  === As a library
114
104
  See the +examples+ directory for examples.
data/Rakefile CHANGED
@@ -11,6 +11,7 @@ begin
11
11
  gem.homepage = "http://github.com/crohr/restfully"
12
12
  gem.authors = ["Cyril Rohr"]
13
13
  gem.add_dependency "rest-client", '>= 1.0'
14
+ gem.add_dependency "backports"
14
15
  gem.rubyforge_project = 'restfully'
15
16
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
16
17
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.2
1
+ 0.4.0
data/bin/restfully CHANGED
@@ -1,19 +1,26 @@
1
1
  #!/usr/bin/env ruby
2
2
  # The command line Restfully client
3
3
 
4
- $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
4
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib' unless $LOAD_PATH.include? File.dirname(__FILE__) + '/../lib'
5
5
 
6
6
  require 'restfully'
7
7
  require 'optparse'
8
8
  require 'logger'
9
9
  require 'yaml'
10
+ require 'pp'
10
11
 
11
12
 
12
13
  logger = Logger.new(STDOUT)
13
14
  logger.level = Logger::WARN
14
15
  @options = {:logger => logger}
15
16
  option_parser = OptionParser.new do |opts|
16
- opts.banner = "Usage: restfully base_uri [root_path] [options]"
17
+ opts.banner = <<BANNER
18
+ * Description
19
+ Restfully #{Restfully::VERSION} - Access REST APIs effortlessly
20
+ * Usage
21
+ restfully [base_uri] [root_path] [options]
22
+ * Options
23
+ BANNER
17
24
 
18
25
  opts.on("-u=", "--username=", "Sets the username") do |u|
19
26
  @options[:username] = u
@@ -43,7 +50,6 @@ end
43
50
  option_parser.parse!
44
51
 
45
52
  @options[:base_uri] = ARGV.shift
46
- @options[:root_path] = ARGV.shift || "/"
47
53
 
48
54
  def session
49
55
  @session ||= Restfully::Session.new(@options)
@@ -51,52 +57,10 @@ end
51
57
 
52
58
  def root
53
59
  @root ||= session.root.load
54
- rescue Restfully::HTTP::Error => e
55
- puts "#{e.class.name}: #{e.message}"
56
60
  end
57
61
 
58
62
  require 'irb'
59
63
  require 'irb/completion'
60
64
  ARGV.clear
61
65
  IRB.start
62
- exit!
63
-
64
-
65
- # if (config_filename = @options.delete('configuration_file')) && File.exists?(File.expand_path(config_filename))
66
- # config = YAML.load_file(File.expand_path(config_filename))
67
- # @base_uri = config.delete('base_uri') || @base_uri
68
- # @root_path = config.delete('root_path') || @root_path
69
- # @options.merge!(config)
70
- # end
71
- #
72
- # unless @base_uri
73
- # $stderr.puts option_parser.help
74
- # exit(-1)
75
- # else
76
- # if (log_file=@options.delete('log'))
77
- # @logger = Logger.new(File.expand_path(log_file))
78
- # else
79
- # @logger = Logger.new(STDOUT)
80
- # end
81
- # if @options.delete('verbose')
82
- # @logger.level = Logger::DEBUG
83
- # else
84
- # @logger.level = Logger::WARN
85
- # end
86
- #
87
- # def session
88
- # @session ||= Restfully::Session.new(@base_uri, @options.merge('root_path' => @root_path, 'logger' => @logger))
89
- # end
90
- # def root
91
- # @root ||= Restfully::Resource.new(session.root_path, session).load
92
- # end
93
- #
94
- # root # preloads
95
- #
96
- # require 'irb'
97
- # require 'irb/completion'
98
- #
99
- # ARGV.clear
100
- # IRB.start
101
- # exit!
102
- # end
66
+ exit!
data/examples/grid5000.rb CHANGED
@@ -5,12 +5,12 @@ require 'pp'
5
5
  require File.dirname(__FILE__)+'/../lib/restfully'
6
6
 
7
7
  logger = Logger.new(STDOUT)
8
- logger.level = Logger::INFO
8
+ logger.level = Logger::WARN
9
9
 
10
10
  # Restfully.adapter = Restfully::HTTP::RestClientAdapter
11
11
  # Restfully.adapter = Patron::Session
12
12
  RestClient.log = 'stdout'
13
- Restfully::Session.new(:base_uri => 'http://api.local/sid', :root_path => '/grid5000', :logger => logger) do |grid, session|
13
+ Restfully::Session.new(:base_uri => 'http://api.local/sid/grid5000', :logger => logger) do |grid, session|
14
14
  grid_stats = {'hardware' => {}, 'system' => {}}
15
15
  grid.sites.each do |site|
16
16
  site_stats = site.status.inject({'hardware' => {}, 'system' => {}}) {|accu, node_status|
@@ -20,9 +20,9 @@ Restfully::Session.new(:base_uri => 'http://api.local/sid', :root_path => '/grid
20
20
  } rescue {'hardware' => {}, 'system' => {}}
21
21
  grid_stats['hardware'].merge!(site_stats['hardware']) { |key,oldval,newval| oldval+newval }
22
22
  grid_stats['system'].merge!(site_stats['system']) { |key,oldval,newval| oldval+newval }
23
- p [site.uid, site_stats]
23
+ p [site['uid'], site_stats]
24
24
  end
25
25
  p [:total, grid_stats]
26
26
  puts "Getting status of a few nodes in rennes:"
27
- pp grid.sites.by_uid('rennes').status(:query => {:only => ['paradent-1', 'paradent-10', 'paramount-3']})
28
- end
27
+ pp grid.sites.find{|s| s['uid'] == 'rennes'}.status(:query => {:only => ['paradent-1', 'paradent-10', 'paramount-3']})
28
+ end
data/lib/restfully.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'backports'
1
2
  require 'restfully/error'
2
3
  require 'restfully/parsing'
3
4
  require 'restfully/http'
@@ -12,9 +13,9 @@ require 'restfully/collection'
12
13
 
13
14
 
14
15
  module Restfully
15
- VERSION = "0.3.2"
16
+ VERSION = "0.4.0"
16
17
  class << self
17
18
  attr_accessor :adapter
18
19
  end
19
20
  self.adapter = Restfully::HTTP::Adapters::RestClientAdapter
20
- end
21
+ end
@@ -1,161 +1,86 @@
1
- require 'delegate'
2
1
 
3
2
  module Restfully
4
- # Resource and Collection classes should clearly include a common module to deal with links, attributes, associations and loading
5
- class Collection < DelegateClass(Array)
6
-
7
- attr_reader :state, :raw, :uri, :session, :title, :offset, :total, :items
3
+ # This includes the <tt>Enumerable</tt> module, but does not have all the
4
+ # methods that you could expect from an <tt>Array</tt>.
5
+ # Remember that this class inherits from a <tt>Restfully::Resource</tt> and
6
+ # as such, the <tt>#[]</tt> method gives access to Resource properties, and
7
+ # not to an item in the collection.
8
+ # If you want to operate on the array of items, you MUST call <tt>#to_a</tt>
9
+ # first (or <tt>#items</tt>) on the Restfully::Collection.
10
+ class Collection < Resource
11
+ include Enumerable
12
+ attr_reader :items
8
13
 
14
+ # See Resource#new
9
15
  def initialize(uri, session, options = {})
10
- options = options.symbolize_keys
11
- @uri = uri
12
- @title = options[:title]
13
- @session = session
14
- reset
15
- super(@items)
16
+ super(uri, session, options)
16
17
  end
17
-
18
- def loaded?; @state == :loaded; end
19
-
18
+
19
+ # See Resource#reset
20
20
  def reset
21
- @last_request_hash = nil
22
- @associations = {}
23
- @attributes = {}
24
- @indexes = {}
25
- @items = []
26
- @raw = nil
27
- @state = :unloaded
21
+ super
22
+ @items = Array.new
23
+ @indexes = Hash.new
24
+ self
28
25
  end
29
26
 
30
- def [](key)
31
- if key.is_a? Symbol
32
- by_uid(key.to_s)
33
- else
34
- super(key)
35
- end
27
+ # Iterates over the collection of items
28
+ def each(*args, &block)
29
+ @items.each(*args, &block)
36
30
  end
37
-
38
- def method_missing(method, *args)
39
- load
40
- if association = @associations[method.to_s]
41
- session.logger.debug "Loading association #{method}, args=#{args.inspect}"
42
- association.load(*args)
43
- elsif method.to_s =~ /^by_(.+)$/
44
- key = $1
45
- @indexes[method.to_s] ||= self.inject({}) { |accu, item|
46
- accu[item.has_key?(key) ? item[key] : item.send(key.to_sym)] = item
47
- accu
48
- }
49
- if args.empty?
50
- @indexes[method.to_s]
51
- elsif args.length == 1
52
- @indexes[method.to_s][args.first]
53
- else
54
- @indexes[method.to_s].values_at(*args)
55
- end
56
- else
57
- super(method, *args)
58
- end
59
- end
60
-
61
- def load(options = {})
62
- options = options.symbolize_keys
63
- force_reload = !!options.delete(:reload)
64
- request_hash = [:get, options].hash
65
- if loaded? && !force_reload && request_hash == @last_request_hash
66
- self
67
- else
68
- reset
69
- @last_request_hash = request_hash
70
- @raw = options[:raw]
71
- if raw.nil? || force_reload
72
- response = session.get(uri, options)
73
- @raw = response.body
74
- end
75
- raw.each do |key, value|
76
- case key
77
- when "total", "offset"
78
- instance_variable_set("@#{key}".to_sym, value)
79
- when "links"
80
- value.each{|link| define_link(Link.new(link))}
81
- when "items"
82
- value.each do |item|
83
- self_link = (item['links'] || []).map{|link| Link.new(link)}.detect{|link| link.self?}
84
- if self_link && self_link.valid?
85
- self.push Resource.new(self_link.href, session).load(:raw => item)
86
- else
87
- session.logger.warn "Resource #{key} does not have a 'self' link. skipped."
88
- end
89
- end
31
+
32
+ def populate_object(key, value)
33
+ case key
34
+ when "links"
35
+ value.each{|link| define_link(Link.new(link))}
36
+ when "items"
37
+ value.each do |item|
38
+ self_link = (item['links'] || []).
39
+ map{|link| Link.new(link)}.detect{|link| link.self?}
40
+ if self_link && self_link.valid?
41
+ @items.push Resource.new(uri.merge(self_link.href), session).load(:body => item)
90
42
  else
91
- case value
92
- when Hash
93
- @attributes.store(key, SpecialHash.new.replace(value)) unless @associations.has_key?(key)
94
- when Array
95
- @attributes.store(key, SpecialArray.new(value))
96
- else
97
- @attributes.store(key, value)
98
- end
43
+ session.logger.warn "Resource #{key} does not have a 'self' link. skipped."
99
44
  end
100
45
  end
101
- @state = :loaded
102
- self
46
+ else
47
+ case value
48
+ when Hash
49
+ @properties.store(key, SpecialHash.new.replace(value)) unless @links.has_key?(key)
50
+ when Array
51
+ @properties.store(key, SpecialArray.new(value))
52
+ else
53
+ @properties.store(key, value)
54
+ end
103
55
  end
56
+ end
57
+
58
+ def inspect
59
+ @items.inspect
104
60
  end
105
61
 
106
- def respond_to?(method, *args)
107
- @associations.has_key?(method.to_s) || super(method, *args)
62
+ # Returns the current number of items (not the total number)
63
+ # in the collection.
64
+ def length
65
+ @items.length
108
66
  end
109
67
 
110
- # Removed: use `y resource` to get pretty output
111
- # def inspect(options = {:space => "\t"})
112
- # output = "#<#{self.class}:0x#{self.object_id.to_s(16)}"
113
- # if loaded?
114
- # output += "\n#{options[:space]}------------ META ------------"
115
- # output += "\n#{options[:space]}@uri: #{uri.inspect}"
116
- # output += "\n#{options[:space]}@offset: #{offset.inspect}"
117
- # output += "\n#{options[:space]}@total: #{total.inspect}"
118
- # @associations.each do |title, assoc|
119
- # output += "\n#{options[:space]}@#{title}: #{assoc.class.name}"
120
- # end
121
- # unless @attributes.empty?
122
- # output += "\n#{options[:space]}------------ PROPERTIES ------------"
123
- # @attributes.each do |key, value|
124
- # output += "\n#{options[:space]}#{key.inspect} => #{value.inspect}"
125
- # end
126
- # end
127
- # unless self.empty?
128
- # output += "\n#{options[:space]}------------ ITEMS ------------"
129
- # self.each do |value|
130
- # output += "\n#{options[:space]}#{value.class.name}"
131
- # end
132
- # end
133
- # end
134
- # output += ">"
135
- # end
136
-
137
- protected
138
- def define_link(link)
139
- if link.valid?
140
- case link.rel
141
- when 'parent'
142
- @associations['parent'] = Resource.new(link.href, session)
143
- when 'collection'
144
- raw_included = link.resolved? ? raw[link.title] : nil
145
- @associations[link.title] = Collection.new(link.href, session,
146
- :raw => raw_included,
147
- :title => link.title)
148
- when 'member'
149
- raw_included = link.resolved? ? raw[link.title] : nil
150
- @associations[link.title] = Resource.new(link.href, session,
151
- :title => link.title,
152
- :raw => raw_included)
153
- when 'self'
154
- # we do nothing
68
+ def pretty_print(pp)
69
+ super(pp) do |pp|
70
+ if @items.length > 0
71
+ pp.breakable
72
+ pp.text "ITEMS (#{self["offset"]}..#{self["offset"]+@items.length})/#{self["total"]}"
73
+ pp.nest 2 do
74
+ @items.each_with_index do |item, i|
75
+ pp.breakable
76
+ pp.text "#<#{item.class}:0x#{item.object_id.to_s(16)} uid=#{item['uid'].inspect}>"
77
+ pp.text "," if i < @items.length-1
78
+ end
79
+ end
155
80
  end
156
- else
157
- session.logger.warn link.errors.join("\n")
158
81
  end
159
82
  end
83
+
84
+ alias_method :size, :length
160
85
  end
161
86
  end