amiando 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. data/.gitignore +6 -0
  2. data/Gemfile +17 -0
  3. data/Guardfile +11 -0
  4. data/README.md +26 -0
  5. data/Rakefile +12 -0
  6. data/amiando.gemspec +27 -0
  7. data/lib/amiando.rb +59 -0
  8. data/lib/amiando/api_key.rb +35 -0
  9. data/lib/amiando/boolean.rb +33 -0
  10. data/lib/amiando/event.rb +131 -0
  11. data/lib/amiando/request.rb +38 -0
  12. data/lib/amiando/resource.rb +152 -0
  13. data/lib/amiando/result.rb +33 -0
  14. data/lib/amiando/ticket_category.rb +99 -0
  15. data/lib/amiando/ticket_shop.rb +63 -0
  16. data/lib/amiando/user.rb +148 -0
  17. data/lib/amiando/version.rb +3 -0
  18. data/test/amiando/amiando_test.rb +13 -0
  19. data/test/amiando/api_key_test.rb +58 -0
  20. data/test/amiando/boolean_test.rb +21 -0
  21. data/test/amiando/event_test.rb +141 -0
  22. data/test/amiando/resource_test.rb +68 -0
  23. data/test/amiando/result_test.rb +25 -0
  24. data/test/amiando/ticket_category_test.rb +89 -0
  25. data/test/amiando/ticket_shop_test.rb +42 -0
  26. data/test/amiando/user_test.rb +130 -0
  27. data/test/fixtures/ApiKey/018fa0a2281ec9026bc122bc346366f6.yml +60 -0
  28. data/test/fixtures/ApiKey/1f62195e173114773b3ec2613582ece9.yml +60 -0
  29. data/test/fixtures/ApiKey/76860dbafe66279f25f56cd66b3f6ba1.yml +62 -0
  30. data/test/fixtures/ApiKey/97d82801a10696aaf385bf5873034b60.yml +60 -0
  31. data/test/fixtures/ApiKey/a703d1fcec1576fa8cb4ca1c5f53f545.yml +62 -0
  32. data/test/fixtures/ApiKey/a948a98b153ab66978e37160f352bfbc.yml +60 -0
  33. data/test/fixtures/ApiKey/b7ecc9e79dd856dec661554cd00490ed.yml +62 -0
  34. data/test/fixtures/ApiKey/ded8694c21d2e1c0cec845f72ba452b5.yml +60 -0
  35. data/test/fixtures/ApiKey/fa883db60c0390aa8948098d32497015.yml +60 -0
  36. data/test/fixtures/Event/29a95cd545b2fba8121dce97a3c859e3.yml +60 -0
  37. data/test/fixtures/Event/361940ebc5f074b1d6d96c2dbeb573ab.yml +60 -0
  38. data/test/fixtures/Event/3a90bf0a17eb1d647f1496d04640797a.yml +60 -0
  39. data/test/fixtures/Event/3b8ae154ad13c7152366b79c0d34b053.yml +60 -0
  40. data/test/fixtures/Event/49877df5f8c251e3364a3560ab1ab46c.yml +60 -0
  41. data/test/fixtures/Event/50cb3d76b40032b0fa5731ce7d2ae2f6.yml +62 -0
  42. data/test/fixtures/Event/5d6016557d86e7b7ff83d07d1ef4bf44.yml +60 -0
  43. data/test/fixtures/Event/67e55d2f91fa702eb8dc612cbfa661f9.yml +60 -0
  44. data/test/fixtures/Event/813535fc6ee153c1a6d8e826f1fe04dc.yml +60 -0
  45. data/test/fixtures/Event/8eabb0f839e03cde5818397c7121e6b4.yml +61 -0
  46. data/test/fixtures/Event/96a5ccd0281a67a4bdb276516b77e756.yml +62 -0
  47. data/test/fixtures/Event/9e689bd5495dc898a710cba8e6d1d779.yml +62 -0
  48. data/test/fixtures/Event/a816e5664ff66b8e3d27b74435a0c123.yml +60 -0
  49. data/test/fixtures/Event/c5ad7e1d1c160d7d1132297892a9ec94.yml +60 -0
  50. data/test/fixtures/Event/c88c85889575508f75deee325e16e49d.yml +60 -0
  51. data/test/fixtures/Event/d6a585196f1a2a94d22f22a2140d4c07.yml +60 -0
  52. data/test/fixtures/Event/e00eebd4faf194fe592fa6e7615909b8.yml +60 -0
  53. data/test/fixtures/Event/e753b6f404795c6635856ea43b0c7d35.yml +60 -0
  54. data/test/fixtures/Event/eb341dbccefaad75aad439f10cc7d82d.yml +60 -0
  55. data/test/fixtures/Event/ebab641e40ca57f8e0883d8ea003bd78.yml +60 -0
  56. data/test/fixtures/Event/ef17351e4bbc84eb776fe16dda31e1e4.yml +62 -0
  57. data/test/fixtures/Global/505952258352958b3b59a3812372ed02.yml +60 -0
  58. data/test/fixtures/Global/d41a6ca323b5db99b4e3c06e108c52cc.yml +60 -0
  59. data/test/fixtures/TicketCategory/0412c9d453efd804e171c6ba57fd980a.yml +66 -0
  60. data/test/fixtures/TicketCategory/49877df5f8c251e3364a3560ab1ab46c.yml +60 -0
  61. data/test/fixtures/TicketCategory/4d3f8d9ff3fb728fc37aaa6e40355a00.yml +62 -0
  62. data/test/fixtures/TicketCategory/5d4fdfda01ed8193c6bbc5e089db5a4b.yml +60 -0
  63. data/test/fixtures/TicketCategory/655e7a8089d67b8eeea1176398e4b289.yml +60 -0
  64. data/test/fixtures/TicketCategory/a9b19dc83437d00ffc4603c04f78159f.yml +62 -0
  65. data/test/fixtures/TicketCategory/bee3d6eb4247fec0849d91fb2f768524.yml +60 -0
  66. data/test/fixtures/TicketCategory/c6f8563714904f006b28ac06312b107d.yml +60 -0
  67. data/test/fixtures/TicketCategory/e6076c26b1b75eec091c5b91c9f75ad9.yml +62 -0
  68. data/test/fixtures/TicketCategory/ebfcf07be91b8cb6d05156713592abc9.yml +60 -0
  69. data/test/fixtures/TicketCategory/fe63648cf867613ec93b380e06257349.yml +60 -0
  70. data/test/fixtures/TicketShop/03d35073550910e61201cf425b4ff73e.yml +60 -0
  71. data/test/fixtures/TicketShop/0524d80dc6e3fad88d49adf71ffa2ab9.yml +60 -0
  72. data/test/fixtures/TicketShop/09729fb0d9f1490bec3acfa0e6742190.yml +60 -0
  73. data/test/fixtures/TicketShop/15c36c73e9f1d3255a61a559e3b98562.yml +60 -0
  74. data/test/fixtures/TicketShop/4605dd240202cd7510bfecaf474ac615.yml +62 -0
  75. data/test/fixtures/TicketShop/5c1f5488a196f44f2c18cc186816fd42.yml +60 -0
  76. data/test/fixtures/TicketShop/71f80402a72be32fdd34074d4426b765.yml +62 -0
  77. data/test/fixtures/TicketShop/bc24338e918c6edb07a55f4d580c5af3.yml +60 -0
  78. data/test/fixtures/TicketShop/d095062bf22d235f277c979b025e5cac.yml +60 -0
  79. data/test/fixtures/TicketShop/ece5150c24e5000bf4eff8dcdb6311bb.yml +60 -0
  80. data/test/fixtures/User/0b4a60c6c962b4b3af9ab21832cd76b2.yml +60 -0
  81. data/test/fixtures/User/0f635f4bb82fdc84af205efe76f43ae0.yml +60 -0
  82. data/test/fixtures/User/1c2f2c8a5372e998f38b9d387107cee2.yml +60 -0
  83. data/test/fixtures/User/1e3ab0fb92b5b1992f35256b4be7497b.yml +71 -0
  84. data/test/fixtures/User/3bac6d29256056f2b9a1ea6fad26966d.yml +60 -0
  85. data/test/fixtures/User/3ffaba64188557400a8678dbefd75990.yml +60 -0
  86. data/test/fixtures/User/5a26c7f9edf6d6027b19b57feda4a96f.yml +60 -0
  87. data/test/fixtures/User/5c17b4b5287f5d0ba390e25e99cf2270.yml +49 -0
  88. data/test/fixtures/User/6501a4db53a97afe6f7b9afeeb996888.yml +60 -0
  89. data/test/fixtures/User/6ad0dd77081f413e3df25d6a625d38cd.yml +60 -0
  90. data/test/fixtures/User/7d493f7758d9795ad522bc827cb51b77.yml +60 -0
  91. data/test/fixtures/User/89e6cb6ae39e29a154c99e0e33bb1b91.yml +60 -0
  92. data/test/fixtures/User/90a3bfe214f17305e356ad3f1a9c9ce7.yml +60 -0
  93. data/test/fixtures/User/92ad6537c8be5aab7cbd778d424f4944.yml +60 -0
  94. data/test/fixtures/User/9485b68940997e23e3721a413d4fbdd5.yml +49 -0
  95. data/test/fixtures/User/98348fe6fbecb7916faadd835916d94d.yml +60 -0
  96. data/test/fixtures/User/b63d7aa4703a3140b4d9884e9f302362.yml +60 -0
  97. data/test/fixtures/User/b8c3fd04d7bd0925c3ccd3a3978ab8e6.yml +49 -0
  98. data/test/fixtures/User/baa28f50439b903e423dbdf918fff20b.yml +62 -0
  99. data/test/fixtures/User/e51278f9f771be0c6c3ac0e4ee1b6459.yml +59 -0
  100. data/test/fixtures/User/eb30a195ac7829d506954f472e9e6dea.yml +60 -0
  101. data/test/support/factory.rb +45 -0
  102. data/test/support/hydra_cache.rb +59 -0
  103. data/test/test_helper.rb +36 -0
  104. metadata +330 -0
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ /.rvmrc
6
+ /TAGS
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in amiando.gemspec
4
+ gemspec
5
+
6
+ unless ENV["TRAVIS"]
7
+ gem 'ruby-debug19', :platforms => :ruby_19
8
+ gem 'ruby-debug', :platforms => :mri_18
9
+ end
10
+
11
+ group :development do
12
+ gem 'guard-minitest'
13
+ if RbConfig::CONFIG['target_os'] =~ /darwin/i
14
+ gem 'rb-fsevent', '>= 0.4.0', :require => false
15
+ gem 'growl', '~> 1.0.3', :require => false
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'minitest' do
5
+ # with Minitest::Unit
6
+ watch(%r|^test/(.*)_test\.rb|)
7
+ watch(%r|^lib/(.*)([^/]+)\.rb|) { |m| "test/#{m[1]}#{m[2]}_test.rb" }
8
+ watch(%r|^test/test_helper\.rb|) { "test" }
9
+ watch(%r|^test/support/(.*)\.rb|) { "test" }
10
+ watch(%r|^lib/amiando.rb|) { "test" }
11
+ end
@@ -0,0 +1,26 @@
1
+ # amiando
2
+
3
+ This is a gem to access the amiando REST API. You can check the original
4
+ documentation here:
5
+
6
+ http://developers.amiando.com/index.php/REST_API
7
+
8
+ ## Basic usage
9
+
10
+ The gem has been implemented with the idea that requests can be done in
11
+ parallel using [Typhoeus](https://github.com/dbalatero/typhoeus).
12
+
13
+ You can query multiple requests and run then like this:
14
+
15
+ ```ruby
16
+ albert = Amiando::User.find(1234)
17
+ jorge = Amiando::User.find(5678)
18
+
19
+ Amiando.run
20
+ ```
21
+
22
+ Both requests will happen in parallel.
23
+
24
+ All attributes should be used in snake_case format instead of the CamelCase
25
+ used in the official documentation. For example, for a user, you should call
26
+ first_name instead of firstName.
@@ -0,0 +1,12 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+
5
+ task :default => :test
6
+
7
+ Rake::TestTask.new do |t|
8
+ t.libs << 'test'
9
+ t.pattern = "test/**/*_test.rb"
10
+ t.verbose = true
11
+ end
12
+ Rake::Task['test'].comment = "Run all tests"
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "amiando/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "amiando"
7
+ s.version = Amiando::VERSION
8
+ s.authors = ["Jorge Dias", "Albert Llop"]
9
+ s.email = ["jorge@mrdias.com","mrsimo@gmail.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{A ruby client for the amiando REST API}
12
+ s.description = %q{A ruby client for the amiando REST API with parallel requests in mind}
13
+
14
+ s.rubyforge_project = "amiando"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency 'yajl-ruby', '0.8.2'
22
+ s.add_dependency 'typhoeus', '0.2.4'
23
+
24
+ s.add_development_dependency 'minitest'
25
+ s.add_development_dependency 'webmock'
26
+ s.add_development_dependency 'rake'
27
+ end
@@ -0,0 +1,59 @@
1
+ require "amiando/version"
2
+ require "typhoeus"
3
+ require "yajl"
4
+
5
+ module Amiando
6
+ autoload :Request, 'amiando/request'
7
+ autoload :Resource, 'amiando/resource'
8
+ autoload :Boolean, 'amiando/boolean'
9
+ autoload :Result, 'amiando/result'
10
+ autoload :ApiKey, 'amiando/api_key'
11
+ autoload :User, 'amiando/user'
12
+ autoload :Event, 'amiando/event'
13
+ autoload :TicketCategory, 'amiando/ticket_category'
14
+ autoload :TicketShop, 'amiando/ticket_shop'
15
+
16
+ module Error
17
+ class ServiceDown < Exception; end
18
+ class ApiKeyNeeded < Exception; end
19
+ class NotAuthorized < Exception; end
20
+ class NotFound < Exception; end
21
+ class NotImplemented < Exception; end
22
+ class NotInitialized < Exception; end
23
+ class MissingApiKey < Exception; end
24
+ end
25
+
26
+ class << self
27
+ attr_accessor :api_key
28
+
29
+ URL = 'https://amiando.com'
30
+ TEST_URL = 'https://test.amiando.com'
31
+
32
+ def production!
33
+ @production = true
34
+ end
35
+
36
+ def development!
37
+ @production = false
38
+ end
39
+
40
+ def base_url
41
+ @production ? URL : TEST_URL
42
+ end
43
+
44
+ def requests
45
+ @requests ||= []
46
+ end
47
+
48
+ def run
49
+ requests.each{ |request| hydra.queue(request) }
50
+ hydra.run
51
+ ensure
52
+ @requests = []
53
+ end
54
+
55
+ def hydra
56
+ @hydra ||= Typhoeus::Hydra.new
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,35 @@
1
+ module Amiando
2
+
3
+ ##
4
+ # http://developers.amiando.com/index.php/REST_API_ApiKey
5
+ class ApiKey < Resource
6
+
7
+ ##
8
+ # Creates an {ApiKey}.
9
+ #
10
+ # @param [Hash] possible attributes that can be set on creation.
11
+ def self.create(attributes)
12
+ raise ArgumentError.new('ApiKey name field is mandatory') unless attributes[:name]
13
+
14
+ object = new
15
+ request = post object, '/api/apiKey/create', :params => attributes
16
+
17
+ object
18
+ end
19
+
20
+ ##
21
+ # Updates an {ApiKey}.
22
+ #
23
+ # @param [Hash] possible attributes that can be updated.
24
+ def self.update(id, attributes)
25
+ object = Boolean.new(:success)
26
+ request = post object, "/api/apiKey/#{id}", :params => attributes
27
+
28
+ object
29
+ end
30
+
31
+ def populate(response_body)
32
+ extract_attributes_from(response_body, 'apiKey')
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,33 @@
1
+ module Amiando
2
+
3
+ ##
4
+ # This object is intended to be used when an api will return a boolean
5
+ # response, but due to the delayed nature of doing requests in parallel,
6
+ # can't be initialized from the beginning.
7
+ #
8
+ # After the object is populated, you can ask the result with the result
9
+ # method.
10
+ class Boolean
11
+ attr_accessor :request, :response
12
+
13
+ def initialize(response_attribute)
14
+ @response_attribute = response_attribute.to_s
15
+ end
16
+
17
+ def populate(response_body)
18
+ if response_body.key?(@response_attribute)
19
+ @result = response_body[@response_attribute]
20
+ else
21
+ raise Error::NotInitialized.new("The response doesn't have the expected attribute")
22
+ end
23
+ end
24
+
25
+ def result
26
+ if defined?(@result)
27
+ @result
28
+ else
29
+ raise Error::NotInitialized.new('Called result before the query was run')
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,131 @@
1
+ module Amiando
2
+
3
+ ##
4
+ # http://developers.amiando.com/index.php/REST_API_Events
5
+ class Event < Resource
6
+ map :host_id, :hostId
7
+ map :selected_date, :selectedDate, :type => :time
8
+ map :selected_end_date, :selectedEndDate, :type => :time
9
+ map :short_description, :shortDescription
10
+ map :event_type, :eventType
11
+ map :organisator_display_name, :organisatorDisplayName
12
+ map :partner_event_url, :partnerEventUrl
13
+ map :publish_search_engines, :publishSearchEngines
14
+ map :search_engine_tags, :searchEngineTags
15
+ map :location_description, :locationDescription
16
+ map :zip_code, :zipCode
17
+ map :creation_time, :creationTime, :type => :time
18
+ map :last_modified, :lastModified, :type => :time
19
+
20
+ ##
21
+ # Creates an event.
22
+ #
23
+ # @return [Event] will not return the full event and only the id attribute
24
+ # will be available.
25
+ def self.create(attributes)
26
+ object = new
27
+ request = post object, '/api/event/create',
28
+ :params => map_params(attributes),
29
+ :populate_method => :populate_create
30
+
31
+ object
32
+ end
33
+
34
+ ##
35
+ # Updates an event.
36
+ #
37
+ # @return [Boolean] if it was successful or not.
38
+ def self.update(id, attributes)
39
+ object = Result.new do |response_body, result|
40
+ unless response_body['success']
41
+ result.errors = response_body['errors']
42
+ end
43
+ response_body['success']
44
+ end
45
+ request = post object, "/api/event/#{id}", :params => map_params(attributes)
46
+
47
+ object
48
+ end
49
+
50
+ ##
51
+ # Fetch an event
52
+ def self.find(id)
53
+ object = new
54
+ request = get object, "/api/event/#{id}"
55
+
56
+ object
57
+ end
58
+
59
+ ##
60
+ # See if an event id exists
61
+ def self.exists?(identifier)
62
+ object = Boolean.new('exists')
63
+ request = get object, "api/event/exists",
64
+ :params => { :identifier => identifier }
65
+
66
+ object
67
+ end
68
+
69
+ ##
70
+ # Deletes an event
71
+ #
72
+ # @param [Integer] event id
73
+ #
74
+ # @return [Boolean] with the result of the operation
75
+ def self.delete(id)
76
+ object = Boolean.new('deleted')
77
+ request = do_request object, :delete, "/api/event/#{id}"
78
+
79
+ object
80
+ end
81
+
82
+ ##
83
+ # Activate an event
84
+ #
85
+ # @param [Integer] the event id
86
+ #
87
+ # @return [Result] if it was activated or not.
88
+ def self.activate(id)
89
+ object = Result.new do |response_body, result|
90
+ unless response_body['success']
91
+ result.errors = response_body['errors']
92
+ end
93
+ response_body['success']
94
+ end
95
+ request = post object, "/api/event/#{id}/activate"
96
+
97
+ object
98
+ end
99
+
100
+ ##
101
+ # Search by identifier or title.
102
+ #
103
+ # @param [Hash] a hash with 1 entry, either :identifier or :title
104
+ #
105
+ # @return [Result] with an array of ids
106
+ def self.search(by)
107
+ unless by[:identifier].nil? ^ by[:title].nil? # XOR
108
+ raise ArgumentError.new('Events can be searched either by identifier or by title, include only one.')
109
+ end
110
+
111
+ object = Result.new { |response_body| response_body['ids'] }
112
+ request = get object, '/api/event/find', :params => by
113
+
114
+ object
115
+ end
116
+
117
+ def self.find_all_by_user_id(user_id)
118
+ object = Result.new do |response_body|
119
+ response_body['events']
120
+ end
121
+ request = get object, "/api/user/#{user_id}/events"
122
+ object
123
+ end
124
+
125
+ private
126
+
127
+ def populate(response_body)
128
+ extract_attributes_from(response_body, 'event')
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,38 @@
1
+ module Amiando
2
+ class Request < Typhoeus::Request
3
+ attr_reader :object
4
+
5
+ def initialize(object, verb, path, params)
6
+ @object = object
7
+
8
+ if verb == :post
9
+ path = build_url(path, default_params)
10
+ else
11
+ path = build_url(path)
12
+ params = default_params.merge(params || {})
13
+ end
14
+
15
+ super(path, :method => verb, :params => params, :verbose => 1)
16
+ end
17
+
18
+ private
19
+
20
+ def default_params
21
+ default = {
22
+ :format => :json,
23
+ :version => 1
24
+ }
25
+ default.merge!(:apikey => Amiando.api_key) if Amiando.api_key
26
+ default
27
+ end
28
+
29
+ def build_url(url, merge_params = {})
30
+ url = URI.join(Amiando.base_url, url).to_s
31
+ unless merge_params.empty?
32
+ query_params = merge_params.map{|k,v| "#{k}=#{v}"}.join('&')
33
+ url = "#{url}?#{query_params}"
34
+ end
35
+ url
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,152 @@
1
+ module Amiando
2
+ class Resource
3
+ attr_accessor :request, :response
4
+ attr_reader :success, :attributes
5
+
6
+ class << self
7
+ def map(local, remote, options = {})
8
+ mapping[local] = remote
9
+ typecasting[local] = options[:type] if options[:type]
10
+ end
11
+
12
+ def typecasting
13
+ @@typecasting ||= {}
14
+ end
15
+
16
+ def mapping
17
+ @@mapping ||= {}
18
+ end
19
+
20
+ ##
21
+ # From { :first_name => '1', :last_name => '2' }
22
+ # to { :firstName => '1', :lastName => '2' }
23
+ def map_params(attributes)
24
+ mapped_attributes = attributes.map do |key,value|
25
+ mapped_key = mapping[key] || key
26
+ value = typecast(key, value)
27
+ [mapped_key, value]
28
+ end
29
+ Hash[mapped_attributes]
30
+ end
31
+
32
+ def reverse_map_params(attributes)
33
+ inverted_mapping = mapping.invert
34
+ mapped_attributes = attributes.map do |key,value|
35
+ key = key.to_sym
36
+ mapped_key = inverted_mapping[key] || key
37
+ value = inverse_typecast(key, value)
38
+ [mapped_key, value]
39
+ end
40
+ Hash[mapped_attributes]
41
+ end
42
+
43
+ private
44
+
45
+ def do_request(object, verb, path, options = {})
46
+ req = Request.new(object, verb, path, options[:params] || {})
47
+ object.request = req
48
+
49
+ req.on_complete do |response|
50
+
51
+ # Raise different errors depending on the return codes
52
+ case response.code
53
+ when 403
54
+ raise Error::NotAuthorized.new(response.body)
55
+ when 404
56
+ raise Error::NotFound.new(response.body)
57
+ when 503
58
+ raise Error::ServiceDown.new(response.body)
59
+ end
60
+
61
+ parsed_body = Yajl::Parser.parse(response.body)
62
+
63
+ if parsed_body['errors'] && parsed_body['errors'].include?('com.amiando.api.rest.MissingParam.apikey')
64
+ raise Error::MissingApiKey.new('This call requires an apikey')
65
+ end
66
+
67
+ object.response = response
68
+ object.send(options[:populate_method] || :populate, parsed_body)
69
+ end
70
+
71
+ Amiando.requests << req
72
+ end
73
+
74
+ def get(object, path, options = {})
75
+ do_request(object, :get, path, options)
76
+ end
77
+
78
+ def post(object, path, options = {})
79
+ do_request(object, :post, path, options)
80
+ end
81
+
82
+ def typecast(key, value)
83
+ if typecasting[key] == :time || value.is_a?(Time)
84
+ value.iso8601
85
+ else
86
+ value
87
+ end
88
+ end
89
+
90
+ def inverse_typecast(key, value)
91
+ if typecasting[key] == :time
92
+ Time.parse(value)
93
+ else
94
+ value
95
+ end
96
+ end
97
+ end
98
+
99
+ def initialize(attributes = nil)
100
+ set_attributes(attributes)
101
+ end
102
+
103
+ def [](key)
104
+ @attributes[key.to_sym]
105
+ end
106
+
107
+ def method_missing(method_name, *args, &block)
108
+ if @attributes.key?(method_name) && args.empty?
109
+ @attributes[method_name]
110
+ else
111
+ super
112
+ end
113
+ end
114
+
115
+ def id
116
+ @attributes[:id]
117
+ end
118
+
119
+ def populate(reponse_body)
120
+ raise Error::NotImplemented.new("populate method not implemented for #{self.class}")
121
+ end
122
+
123
+ def populate_create(response_body)
124
+ @attributes = {:id => response_body['id'], :errors => response_body['errors']}
125
+ @success = response_body['success']
126
+ end
127
+
128
+ def extract_attributes_from(response_body, key)
129
+ @attributes = {}
130
+
131
+ set_attributes(response_body[key])
132
+
133
+ @success = response_body['success']
134
+ end
135
+
136
+ def ==(resource)
137
+ id == resource.id
138
+ end
139
+
140
+ protected
141
+
142
+ def set_attributes(attributes)
143
+ @attributes = {}
144
+
145
+ if attributes
146
+ self.class.reverse_map_params(attributes).each do |k,v|
147
+ @attributes[k.to_sym] = v
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end