swivel 0.0.21 → 0.0.96

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.
Files changed (4) hide show
  1. data/Rakefile +0 -1
  2. data/bin/swivel +5 -16
  3. data/lib/swivel.rb +292 -91
  4. metadata +2 -12
data/Rakefile CHANGED
@@ -64,7 +64,6 @@ spec =
64
64
 
65
65
  s.add_dependency 'activesupport'
66
66
  s.add_dependency 'cobravsmongoose'
67
- s.add_dependency 'json'
68
67
  end
69
68
 
70
69
  Rake::GemPackageTask.new(spec) do |p|
data/bin/swivel CHANGED
@@ -3,11 +3,8 @@
3
3
  require 'rubygems'
4
4
  require 'active_support' # TODO: make it work w/o this
5
5
  require 'optparse'
6
- require File.dirname(__FILE__) + '/../lib/swivel'
7
6
  require 'yaml'
8
-
9
- #require 'ruby-debug'
10
- #Debugger.start
7
+ require File.dirname(__FILE__) + '/../lib/swivel'
11
8
 
12
9
  options = Hash.new
13
10
  config = Swivel::Connection::Config.new
@@ -67,12 +64,12 @@ class SwivelHelper
67
64
 
68
65
  def show resource, id
69
66
  resource = resource.pluralize
70
- response = @swivel.call "/rest/#{resource}/#{id}"
67
+ response = @swivel.call "/#{resource}/#{id}"
71
68
  end
72
69
 
73
70
  def list resource, options = Hash.new
74
71
  resource = resource.pluralize
75
- response = @swivel.call "/rest/#{resource}", options
72
+ response = @swivel.call "/#{resource}", options
76
73
  end
77
74
 
78
75
  def upload name, options = Hash.new
@@ -89,21 +86,13 @@ class SwivelHelper
89
86
 
90
87
  def append id, options = Hash.new
91
88
  filename = options[:filename]
92
- data_set = @swivel.append :id => id,
93
- :original_asset_name => filename,
94
- :original_asset_path => filename,
95
- :auto_estimate => true,
96
- :data => read(filename)
89
+ data_set = @swivel.append :id => id, :data => read(filename)
97
90
  puts "appended #{data_set.id}"
98
91
  end
99
92
 
100
93
  def replace id, options = Hash.new
101
94
  filename = options[:filename]
102
- data_set = @swivel.replace :id => id,
103
- :original_asset_name => filename,
104
- :original_asset_path => filename,
105
- :auto_estimate => true,
106
- :data => read(filename)
95
+ data_set = @swivel.replace :id => id, :data => read(filename)
107
96
  puts "replaced #{data_set.id}"
108
97
  end
109
98
 
data/lib/swivel.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'rubygems'
2
2
  require 'active_support' # TODO: make this work w/o active_support?
3
3
  require 'base64'
4
+ require 'benchmark'
4
5
  require 'cgi'
5
6
  require 'cobravsmongoose'
6
7
  require 'fileutils'
@@ -8,6 +9,10 @@ require 'net/http'
8
9
  require 'rexml/document'
9
10
  require 'yaml'
10
11
 
12
+ class Time
13
+ RFC822_DATETIME_REGEX = /\w{3}, \d{2} \w{3} \d{4} \d{2}:\d{2}:\d{2} [+-]\d{4}/
14
+ end
15
+
11
16
  class String
12
17
 
13
18
  # Returns true if the string looks numeric
@@ -15,7 +20,9 @@ class String
15
20
  # 'howdy'.numeric? # => false
16
21
 
17
22
  def numeric?
18
- (self =~ /^-?\d+(\.\d+|\d*)$/) != nil
23
+ # work around the bug in ruby ^ regexp matching
24
+ string_sans_newlines = self.gsub(/\r|\n/, ' ')
25
+ (string_sans_newlines =~ /^-?\d+(\.\d+|\d*)$/) != nil
19
26
  end
20
27
 
21
28
  # Returns the string with '_' translated to '-'
@@ -37,19 +44,7 @@ class String
37
44
  # 'DataSet'.to_xml_tag # => "data-set"
38
45
 
39
46
  def to_xml_tag
40
- self.underscore.dashify
41
- end
42
- end
43
-
44
- class Hash
45
-
46
- # Returns a query string generated from keys and values. CGI escaped, of course.
47
- # { :name => 'huned', :year => 2007 }.to_query_string # => "name=huned&year=2007"
48
-
49
- def to_query_string
50
- keys.map do |k|
51
- "#{CGI.escape k.to_s}=#{CGI.escape self[k].to_s}"
52
- end.join('&')
47
+ self.underscore.dasherize
53
48
  end
54
49
  end
55
50
 
@@ -123,8 +118,6 @@ end
123
118
 
124
119
  module Swivel
125
120
 
126
- class ApiError < StandardError; end
127
-
128
121
  # Encapsulates XML that Swivel returns from an API call. Generally, you'll
129
122
  # never need to instantiate a Swivel::Response object. Use one of its subclasses
130
123
  # instead:
@@ -135,23 +128,23 @@ module Swivel
135
128
  # * Swivel::DataColumn
136
129
  # * Swivel::Graph
137
130
  # * Swivel::User
138
- #
131
+ # * others
139
132
 
140
133
  class Response
141
134
 
142
- attr_accessor :refreshed_at
135
+ attr_accessor :refreshed_at, :disable_auto_refresh
136
+
137
+ def self.resource
138
+ nil
139
+ end
143
140
 
144
141
  # Instantiate from XML returned from Swivel.
145
142
  def initialize xml = nil, connection = nil
146
143
  @connection = connection
147
- @xml_tag = self.class.name.split('::').last.to_xml_tag
144
+ @disable_auto_refresh = @connection && @connection.disable_auto_refresh
145
+ @xml_tag = self.class.name.demodulize.to_xml_tag
148
146
  @doc = REXML::Document.new xml
149
147
  if @response = REXML::XPath.first(@doc, '/response')
150
- if error = REXML::XPath.first(@doc, '/response/error')
151
- message = error.attribute('message').to_s
152
- code = error.attribute('code').to_s
153
- raise ApiError, "#{message} (#{code})"
154
- end
155
148
  # if it's a full response, strip away the outer cruft
156
149
  @doc = REXML::Document.new @response.elements[1].to_s
157
150
  end
@@ -161,29 +154,30 @@ module Swivel
161
154
  # pretty flexible in what it returns:
162
155
  #
163
156
  # * text from attributes
164
- # data_set = swivel.call '/rest/data_sets/1005309'
157
+ # data_set = swivel.call '/data_sets/1005309'
165
158
  # data_set.to_xml # => "<data-set swivel-id=\"1005309\"> ..."
166
159
  #
167
160
  # # invokes method_missing
168
161
  # data_set.id # => 1005309
169
162
  # * text from elements
170
- # data_set = swivel.call '/rest/data_sets/1005309'
163
+ # data_set = swivel.call '/data_sets/1005309'
171
164
  # data_set.to_xml # => "<data-set ...><name>Swivel API</name> ..."
172
165
  #
173
166
  # # invokes method_missing
174
167
  # data_set.name # => "Swivel API"
175
168
  # * objects that inherit from Swivel::Response (including Swivel::List)
176
- # data_set = swivel.call '/rest/data_sets/1005309'
169
+ # data_set = swivel.call '/data_sets/1005309'
177
170
  # data_set.to_xml # => "<data-set ...><user swivel-id=\"1000010\"> ..."
178
171
  #
179
172
  # # invokes method_missing
180
173
  # data_set.user.class # => Swivel::User
181
174
 
182
175
  def method_missing method_id
183
- select_element = "/#{@xml_tag}/#{method_id.to_s.to_xml_tag}"
184
- select_attribute = "/#{@xml_tag}/@#{method_id.to_s.to_xml_tag}"
185
- select_list = "/#{@xml_tag}/list[@resource=\"#{method_id.to_s.singularize.to_xml_tag}\"]"
176
+ select_element = "/#{self.class.resource ? self.class.resource : @xml_tag}/#{method_id.to_s.to_xml_tag}"
177
+ select_attribute = "/#{self.class.resource ? self.class.resource : @xml_tag}/@#{method_id.to_s.to_xml_tag}"
178
+ select_list = "/#{self.class.resource ? self.class.resource : @xml_tag}/list[@resource=\"#{method_id.to_s.singularize.to_xml_tag}\"]"
186
179
 
180
+
187
181
  if el = REXML::XPath.first(@doc, select_element)
188
182
  if el.attribute('swivel-id')
189
183
  Response.class_for(el.name).new(el.to_s, @connection)
@@ -200,8 +194,8 @@ module Swivel
200
194
  raise NoMethodError, "#{method_id} isn't a method of #{self.class.name}"
201
195
  end
202
196
  rescue Exception => e
203
- if @retried || @refreshed_at
204
- raise e
197
+ if @disable_auto_refresh || @retried || @refreshed_at
198
+ nil
205
199
  else
206
200
  @retried = true
207
201
  refresh! true
@@ -209,25 +203,43 @@ module Swivel
209
203
  end
210
204
  end
211
205
 
206
+ # Alternate access to properties. Same as dot notation, so user[:name] == user.name
207
+
208
+ def [](attribute)
209
+ case attribute
210
+ when Symbol, String
211
+ self.send(attribute)
212
+ else
213
+ super
214
+ end
215
+ end
216
+
212
217
  # Returns the unique id in swivel for this object. Ids are unique
213
218
  # for each resource.
214
- # user = swivel.call '/rest/users/1000010'
219
+ # user = swivel.call '/users/1000010'
215
220
  # user.id # => 1000010
216
221
  # user.id == user.swivel_id # => true
217
222
 
218
223
  def id
219
224
  swivel_id
220
225
  end
226
+
227
+ # Same as id method, added to make Swivel objects play well with url_for
228
+ # in Rails.
229
+
230
+ def to_param
231
+ id.to_s
232
+ end
221
233
 
222
234
  # Refreshes the object's content from Swivel.
223
235
  #
224
- # data_set = swivel.call '/rest/data_sets/1005309'
236
+ # data_set = swivel.call '/data_sets/1005309'
225
237
  # user = data_set.user
226
238
  # user.refresh! # populate the object fully from Swivel
227
239
 
228
240
  def refresh! force = false
229
241
  if @connection && (force || @refreshed_at.blank?)
230
- refreshed = @connection.call "/rest/#{@xml_tag.undashify}s/#{id}"
242
+ refreshed = @connection.call "/#{@xml_tag.undashify}s/#{id}"
231
243
  if refreshed.is_a? self.class
232
244
  @doc = REXML::Document.new refreshed.to_xml
233
245
  @refreshed_at = Time.now
@@ -237,13 +249,19 @@ module Swivel
237
249
  end
238
250
 
239
251
  # Returns the underlying XML string for this object as a string.
240
- # user = swivel.call '/rest/users/1000010'
252
+ # user = swivel.call '/users/1000010'
241
253
  # puts user.to_xml
242
254
 
243
255
  def to_xml
244
256
  @doc.to_s
245
257
  end
246
258
 
259
+ # Try to be somewhat useful about to_s. Maybe not great.
260
+
261
+ def to_s
262
+ self.class.name.demodulize + ' ' + (name || title || inspect)
263
+ end
264
+
247
265
  protected
248
266
  # Return an appropriate Swivel::Response subclass for the given resource.
249
267
  # Swivel::Response.class_for 'data-set' # => Swivel::DataSet
@@ -251,20 +269,72 @@ module Swivel
251
269
  # Swivel::Response.class_for 'list' # => Swivel::List
252
270
 
253
271
  def self.class_for resource
254
- "Swivel::#{resource.undashify.classify}".constantize
272
+ new_class_name = resource.undashify.classify
273
+ "Swivel::#{new_class_name}".constantize
274
+ rescue NameError => e
275
+ Swivel.const_set new_class_name.to_sym, Class.new(Swivel::Response)
276
+ returning "Swivel::#{new_class_name}".constantize do |c|
277
+ c.class_eval "def self.resource; '#{resource}'; end"
278
+ end
255
279
  rescue
256
280
  nil
257
281
  end
258
282
 
259
283
  def value_for s #:nordoc:
260
- s.numeric? ? s.to_i : s
284
+ if s.match Time::RFC822_DATETIME_REGEX
285
+ Time.parse s
286
+ elsif s.numeric?
287
+ s.to_i
288
+ else
289
+ s
290
+ end
261
291
  end
262
292
  end
263
293
 
264
- %w/DataColumn User/.each do |class_name|
265
- class_eval <<-LAZY
266
- class #{class_name} < Response; end
267
- LAZY
294
+ class Annotation < Response; end
295
+ class Comment < Response; end
296
+ class Page < Response; end
297
+ class PageAsset < Response; end
298
+ class Prose < Response; end
299
+
300
+ class Permission < Response
301
+ %w/accessor accessable/.each do |thing|
302
+ define_method thing.to_sym do
303
+ unless instance_variable_get "@#{thing}".to_sym
304
+ c =
305
+ begin
306
+ dashified = thing.dasherize
307
+ o = REXML::XPath.first(@doc, "/permission/#{dashified}").elements[1]
308
+ Response.class_for(o.name).new o.to_s
309
+ rescue
310
+ warn e
311
+ nil
312
+ end
313
+ instance_variable_set "@#{thing}", c
314
+ end
315
+ instance_variable_get "@#{thing}"
316
+ end
317
+ end
318
+ end
319
+
320
+ class Activity < Response
321
+ %w/source subject verb direct_object prepositional_object/.each do |part|
322
+ define_method part.to_sym do
323
+ unless instance_variable_get "@#{part}".to_sym
324
+ c =
325
+ begin
326
+ dashified = part.dasherize
327
+ o = REXML::XPath.first(@doc, "/activity/#{dashified}").elements[1]
328
+ Response.class_for(o.name).new o.to_s
329
+ rescue
330
+ warn e
331
+ nil
332
+ end
333
+ instance_variable_set "@#{part}", c
334
+ end
335
+ instance_variable_get "@#{part}"
336
+ end
337
+ end
268
338
  end
269
339
 
270
340
  class DataSet < Response
@@ -301,15 +371,61 @@ module Swivel
301
371
  @doc = replaced_data_set.instance_variable_get :@doc
302
372
  self
303
373
  end
374
+
375
+ def csv
376
+ @connection.call "/data_sets/csv/#{id}"
377
+ end
378
+ end
379
+
380
+ class Visual < Response
381
+
382
+ ## Forms the url for an image.
383
+ def image_url options={}
384
+ options = {:format => "png", :s => Time.now.to_i, :secret => secret}.merge(options)
385
+ host, port = @connection.config[:host], @connection.config[:port]
386
+ port = port == 80 ? '' : ":#{port}"
387
+ url = "http://#{host}#{port}/visuals/#{id}.#{options.delete(:format)}?#{@connection.requestify(options)}"
388
+
389
+ end
390
+ end
391
+
392
+ class User < Response
393
+ def admin?
394
+ admin.to_b
395
+ rescue
396
+ false
397
+ end
398
+
399
+ def to_param
400
+ name
401
+ end
402
+ end
403
+
404
+ class Group < Response
405
+ def members
406
+ @members ||=
407
+ begin
408
+ o = REXML::XPath.first(@doc, "/group/members").elements[1]
409
+ Response.class_for(o.name).new o.to_s
410
+ rescue
411
+ warn e
412
+ nil
413
+ end
414
+ end
415
+
416
+ def to_param
417
+ (!slug.blank? and slug) or super.to_param
418
+ end
304
419
  end
305
420
 
306
421
  class Graph < Response
307
422
  def image_url options = Hash.new
308
- host = @connection.config[:image_host]
423
+ host, port = @connection.config[:host], @connection.config[:port]
424
+ port = port == 80 ? '' : ":#{port}"
309
425
  if variant == 'transient'
310
- "http://#{host}/graphs/get/#{digest}"
426
+ "http://#{host}#{port}/graphs/get/#{digest}"
311
427
  else
312
- "http://#{host}/graphs/image/#{id}"
428
+ "http://#{host}#{port}/graphs/image/#{id}"
313
429
  end
314
430
  end
315
431
 
@@ -336,10 +452,10 @@ module Swivel
336
452
  def save!
337
453
  return self unless variant == 'transient'
338
454
  options = {:save => 'true', :digest => self.digest}
339
- # PUT /rest/graphs/0 denotes updating a transient graph. Swivel
455
+ # PUT /graphs/0 denotes updating a transient graph. Swivel
340
456
  # will read the digest and save the transient graph that matches
341
457
  # that digest.
342
- saved_graph = @connection.call '/rest/graphs/0', options, :put
458
+ saved_graph = @connection.call '/graphs/0', options, :put
343
459
  @doc = saved_graph.instance_variable_get :@doc
344
460
  @refreshed_at = nil
345
461
  @retried = false
@@ -350,11 +466,11 @@ module Swivel
350
466
  # Encapsulates lists of resources. Typically, items contained within the list are
351
467
  # subclasses of Swivel::Response.
352
468
  #
353
- # data_sets = swivel.call '/rest/data_sets'
469
+ # data_sets = swivel.call '/data_sets'
354
470
  # data_sets.class # => Swivel::List
355
471
  # data_sets.collect do |d| d.class end # => [Swivel::DataSet, Swivel::DataSet, ...]
356
472
  #
357
- # users = swivel.call '/rest/users'
473
+ # users = swivel.call '/users'
358
474
  # users.class # => Swivel::List
359
475
  # users.collect do |u| u.class end # => [Swivel::User, Swivel::User, ...]
360
476
 
@@ -366,6 +482,7 @@ module Swivel
366
482
  unless @processed
367
483
  @list = Array.new
368
484
  resource = @doc.elements[1].attributes['resource']
485
+ resource ||= @doc.elements[1].elements[1].name
369
486
  selector = "/list/#{resource}"
370
487
  REXML::XPath.each @doc, selector do |e|
371
488
  @list << Response.class_for(resource).new(e.to_s, @connection)
@@ -374,20 +491,36 @@ module Swivel
374
491
  end
375
492
  end
376
493
 
377
- def refresh!
494
+ def refresh! force = false
378
495
  self # don't call refresh! on a list
379
496
  end
380
497
 
498
+ # Get the underlying Array for this Swivel::List object.
499
+
500
+ def to_a
501
+ @list
502
+ end
503
+
381
504
  # Delegates methods to the underlying Array instance. Allows you to
382
505
  # call Array methods on a Swivel::List.
383
506
  #
384
- # data_sets = swivel.call '/rest/data_sets'
507
+ # data_sets = swivel.call '/data_sets'
385
508
  # # try some Array methods...
386
509
  # data_sets.length.is_a? Integer # => true
387
510
  # data_sets.first.is_a? Swivel::DataSet #=> true
388
511
 
389
512
  def method_missing method_id, *args, &block
390
513
  @list.send method_id, *args, &block
514
+ rescue NoMethodError => e
515
+ super
516
+ end
517
+ end
518
+
519
+ class ApiError < StandardError; end
520
+
521
+ class Error < Response
522
+ def raise
523
+ super ApiError, message, backtrace.split("\n")
391
524
  end
392
525
  end
393
526
 
@@ -408,11 +541,12 @@ module Swivel
408
541
 
409
542
  class Config
410
543
  CONFIG_DIR = ENV['HOME']
544
+ CONFIG_DIR = RAILS_ROOT if PLATFORM.include?('win32')
411
545
  CONFIG_FILE = '.swivelrc'
412
546
  DEFAULT_HOST = 'api.swivel.com'
413
547
  DEFAULT_CONFIG = { :api_key => '', :protocol => 'http://',
414
548
  :host => DEFAULT_HOST, :port => 80,
415
- :timeout_up => 200, :timeout_down => 100 }
549
+ :timeout_up => 200, :timeout_down => 100, :path_prefix => '', :logfile => nil }
416
550
 
417
551
  attr_accessor :config
418
552
 
@@ -433,8 +567,6 @@ module Swivel
433
567
  else
434
568
  YAML::load_file @filename
435
569
  end
436
- @config[:image_host] ||=
437
- @config[:host] == DEFAULT_HOST ? 'www.swivel.com' : @config[:host]
438
570
  @config
439
571
  end
440
572
 
@@ -446,7 +578,7 @@ module Swivel
446
578
  end
447
579
  end
448
580
 
449
- attr_accessor :config
581
+ attr_accessor :config, :disable_auto_refresh
450
582
 
451
583
  # Instantiate a connection to Swivel. Use the connection to query or upload,
452
584
  # append, or replace data. Passed in options will take precedence over values
@@ -454,26 +586,33 @@ module Swivel
454
586
 
455
587
  def initialize options = Hash.new
456
588
  @config = Config.new.config
457
- @config.keys.each do |key|
458
- @config[key] = options[key] if options.has_key? key
459
- end
589
+ @config.merge! options
460
590
  @headers = options[:headers] || Hash.new
461
591
  @headers.merge! 'Accept' => 'application/xml'
462
592
  end
463
593
 
594
+ # Keep track of how many calls have been made. Note that this means
595
+ # multiple Swivel::Connection instances increment the same call count
596
+ # if those Swivel::Connections run within the same thread.
597
+ cattr_accessor :calls
598
+ @@calls = []
599
+ def self.reset_calls!
600
+ @@calls = []
601
+ end
602
+
464
603
  # Call Swivel's REST endpoint. This method actually performs the HTTP stuff
465
604
  # that you need. and returns objects constructed from the returned XML. If an
466
605
  # appropriate class is not available, just returns the XML string.
467
606
  #
468
607
  # # returns an object that's a subclass of Swivel::Response
469
- # user = swivel.call '/rest/users/1000010'
608
+ # user = swivel.call '/users/1000010'
470
609
  # user.class # => Swivel::User
471
610
  #
472
- # users = swivel.call '/rest/users'
611
+ # users = swivel.call '/users'
473
612
  # users.class # => Swivel::List
474
613
  #
475
614
  # # returns a string (because an appropriate Swivel::Response subclass doesn't exist)
476
- # echo = swivel.call '/rest/test/echo/howdy'
615
+ # echo = swivel.call '/test/echo/howdy'
477
616
  # echo.class # => String
478
617
  #
479
618
  # However, calling all of those endpoints is tedious. For swivel's main objects
@@ -492,56 +631,97 @@ module Swivel
492
631
  #
493
632
  # All these convenience methoods (yeah, methoods) really do is prettify a get call
494
633
  # to:
495
- # /rest/object_type or /rest/object_type/id
496
-
497
- def call path, params = Hash.new, method = :get
498
- response =
499
- Net::HTTP.start @config[:host], @config[:port] do |http|
500
- request_class = "Net::HTTP::#{method.to_s.camelize}".constantize
501
- request = request_class.new path, headers
502
- if [:delete, :post, :put].include? method
503
- http.read_timeout = @config[:timeout_up]
504
- http.request request, params.to_query_string
505
- else
506
- http.read_timeout = @config[:timeout_down]
507
- http.request request
634
+ # /object_type or /object_type/id
635
+ def call path, params = Hash.new, method = :get, extra_headers = Hash.new
636
+ path, query_string = path.split("?")
637
+ params = requestify(params)
638
+ query_string += "&" if params and query_string
639
+ params = "#{query_string}#{params}"
640
+ path = "/#{config[:path_prefix]}#{path}" unless config[:path_prefix].blank?
641
+ response = nil
642
+ elapsed_time = Benchmark.realtime do
643
+ response =
644
+ Net::HTTP.start config[:host], config[:port] do |http|
645
+ request_class = "Net::HTTP::#{method.to_s.camelize}".constantize
646
+ if [:delete, :post, :put].include? method
647
+ request = request_class.new path, headers.merge(extra_headers)
648
+ http.read_timeout = config[:timeout_up]
649
+ http.request request, params
650
+ else
651
+ request = request_class.new "#{path}?#{params}", headers.merge(extra_headers)
652
+ http.read_timeout = config[:timeout_down]
653
+ http.request request
654
+ end
508
655
  end
509
- end
510
- response.error! if response.code.to_i >= 300
511
- xml = response.body
512
- doc = REXML::Document.new xml
513
- Response.class_for(doc.root.elements[1].name).new xml, self
656
+ end
657
+ @@calls << {:url => path, :time => elapsed_time}
658
+ body = response.body
659
+ log body
660
+ case response.content_type
661
+ when 'application/xml'
662
+ doc = REXML::Document.new body
663
+ Response.class_for(doc.root.elements[1].name).new body, self
664
+ when 'text/csv', 'text/plain'
665
+ body
666
+ else
667
+ raise "Unknown content type: #{response.content_type}"
668
+ end
514
669
  rescue Exception => e
515
670
  #xml.blank? ? nil : xml
516
- warn "Failure while communicating with swivel: #{xml}\n"
671
+ warn "Failure while communicating with swivel"
672
+ warn "Request: #{config[:host]}:#{config[:port]}#{path}"
673
+ warn "Response: #{body}"
517
674
  raise e
518
675
  end
519
676
 
520
- %w/ data_columns data_sets graphs users /.each do |obj|
677
+ def call! *args
678
+ returning call(*args) do |r|
679
+ r.raise if Swivel::Error === r
680
+ end
681
+ end
682
+
683
+ def log str
684
+ unless config[:logfile] == nil
685
+ unless @logger
686
+ @logger = Logger.new(config[:logfile])
687
+ @logger.level = Logger::INFO
688
+ end
689
+ @logger.info(str)
690
+ end
691
+ end
692
+
693
+ %w/ data_columns data_sets graphs roles submissions users groups /.each do |obj|
521
694
  class_eval <<-LAZY
522
695
  def #{obj} options = nil
523
696
  case options
524
697
  when Hash
525
698
  if options[:id]
526
- call "/rest/#{obj}/#\{options[:id]\}", options
699
+ call "/#{obj}/#\{options[:id]\}", options
527
700
  else
528
- call "/rest/#{obj}", options, :post
701
+ call "/#{obj}", options, :post
529
702
  end
530
703
  when Numeric, String, Symbol
531
- call "/rest/#{obj}/#\{options\}"
704
+ call "/#{obj}/#\{options\}"
532
705
  else
533
- call '/rest/#{obj}'
706
+ call '/#{obj}'
534
707
  end
535
708
  end
536
709
  alias :#{obj.singularize} :#{obj}
710
+
711
+ def #{obj}! *args
712
+ returning #{obj}(*args) do |r|
713
+ r.raise if Swivel::Error === r
714
+ end
715
+ end
716
+ alias :#{obj.singularize}! :#{obj}!
537
717
  LAZY
538
718
  end
539
719
 
540
720
  DEFAULT_UPLOAD_OPTIONS = {
541
721
  :citation => 'swivel.rb',
542
- :citation_url => 'swivel.com/developer',
722
+ :citation_url => 'www.swivel.com/developer',
543
723
  :image_url => 'http://www.swivel.com/images/logo.png',
544
- :image_source_url => 'http://swivel.com',
724
+ :image_source_url => 'http://www.swivel.com',
545
725
  :display_tags => 'swivel api swivel.rb'
546
726
  }
547
727
 
@@ -595,13 +775,13 @@ module Swivel
595
775
  case opts[:mode]
596
776
  when 'append', 'replace'
597
777
  opts[:auto_estimate] = true
598
- ["/rest/data_sets/#{opts[:id]}", :put]
778
+ ["/data_sets/#{opts[:id]}", :put]
599
779
  else
600
780
  force_auto_estimate =
601
- !opts.has_key?(:auto_estimate) && !opts.has_key?(:column_type)
781
+ !opts.has_key?(:auto_estimate) && !opts.has_key?(:column_types)
602
782
  opts[:auto_estimate] = true if force_auto_estimate
603
783
  opts.reverse_merge! DEFAULT_UPLOAD_OPTIONS
604
- ['/rest/data_sets', :post]
784
+ ['/data_sets', :post]
605
785
  end
606
786
  call uri, opts, method
607
787
  end
@@ -698,10 +878,30 @@ module Swivel
698
878
  options.merge! :order_by_column => options[:columns].split(',').first,
699
879
  :order_by_direction => 'DESC'
700
880
  end
701
- call '/rest/graphs', options, :post
881
+ call '/graphs', options, :post
882
+ end
883
+
884
+ # copied verbatim from actioncontroller::integration::session
885
+
886
+ def requestify(parameters, prefix=nil)
887
+ if Hash === parameters
888
+ return nil if parameters.empty?
889
+ parameters.map { |k,v| requestify(v, name_with_prefix(prefix, k)) }.join("&")
890
+ elsif Array === parameters
891
+ parameters.map { |v| requestify(v, name_with_prefix(prefix, "")) }.join("&")
892
+ elsif prefix.nil?
893
+ parameters
894
+ else
895
+ "#{CGI.escape(prefix)}=#{CGI.escape(parameters.to_s)}"
896
+ end
897
+ end
898
+
899
+ def name_with_prefix(prefix, name)
900
+ prefix ? "#{prefix}[#{name}]" : name.to_s
702
901
  end
703
902
 
704
903
  protected
904
+
705
905
  def headers
706
906
  if @config.has_key?(:api_key) && !@config[:api_key].blank?
707
907
  encoded = Base64.encode64(':' + @config[:api_key])
@@ -710,5 +910,6 @@ module Swivel
710
910
  @headers
711
911
  end
712
912
  end
913
+
713
914
  end
714
915
  end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
3
3
  specification_version: 1
4
4
  name: swivel
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.0.21
7
- date: 2007-08-08 00:00:00 -07:00
6
+ version: 0.0.96
7
+ date: 2007-10-12 00:00:00 -07:00
8
8
  summary: Ruby interface to the Swivel API.
9
9
  require_paths:
10
10
  - lib
@@ -33,7 +33,6 @@ files:
33
33
  - README
34
34
  - Rakefile
35
35
  - lib/swivel.rb
36
- - lib/test
37
36
  - bin/swivel
38
37
  - CHANGELOG
39
38
  test_files: []
@@ -74,12 +73,3 @@ dependencies:
74
73
  - !ruby/object:Gem::Version
75
74
  version: 0.0.0
76
75
  version:
77
- - !ruby/object:Gem::Dependency
78
- name: json
79
- version_requirement:
80
- version_requirements: !ruby/object:Gem::Version::Requirement
81
- requirements:
82
- - - ">"
83
- - !ruby/object:Gem::Version
84
- version: 0.0.0
85
- version: