point 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,27 @@
1
+ ## Require dependencies. All network traffic is processed using net/http and
2
+ ## is transfered using JSON.
3
+ require 'json'
4
+ require 'uri'
5
+ require 'net/http'
6
+
7
+ ## PointHQ Ruby API Client
8
+ ## This is a ruby API client for the Point DNS hosting service.
9
+
10
+ require 'point/request'
11
+ require 'point/errors'
12
+ require 'point/base'
13
+ require 'point/zone'
14
+ require 'point/zone_record'
15
+
16
+ module Point
17
+ VERSION = '1.0.0'
18
+
19
+ class << self
20
+ attr_accessor :username
21
+ attr_accessor :apitoken
22
+ attr_accessor :site
23
+ end
24
+
25
+ end
26
+
27
+ Point.site = "http://pointhq.com"
@@ -0,0 +1,160 @@
1
+ module Point
2
+ class Base
3
+
4
+ ## Store all attributes for the model we're working with.
5
+ attr_accessor :id, :attributes, :errors
6
+
7
+ ## Pass any methods via. the attributes hash to see if they exist
8
+ ## before resuming normal method_missing behaviour
9
+ def method_missing(method, *params)
10
+ set = method.to_s.include?('=')
11
+ key = method.to_s.sub('=', '')
12
+ self.attributes = Hash.new unless self.attributes.is_a?(Hash)
13
+ if set
14
+ self.attributes[key] = params.first
15
+ else
16
+ self.attributes[key]
17
+ end
18
+ end
19
+
20
+ class << self
21
+
22
+ ## Find a record or set of records. Passing :all will return all records and passing an integer
23
+ ## will return the individual record for the ID passed.
24
+ def find(type, params = {})
25
+ case type
26
+ when :all then find_all(params)
27
+ when Integer then find_single(type, params)
28
+ end
29
+ end
30
+
31
+ ## Find all objects and return an array of objects with the attributes set.
32
+ def find_all(params)
33
+ JSON.parse(Request.new(collection_path(params)).make.output).map do |o|
34
+ create_object(o[class_name.downcase], params)
35
+ end
36
+ end
37
+
38
+ ## Find a single object and return an object for it.
39
+ def find_single(id, params = {})
40
+ o = JSON.parse(Request.new(member_path(id, params)).make.output)
41
+ if o[class_name.downcase]
42
+ create_object(o[class_name.downcase], params)
43
+ else
44
+ raise Point::Errors::NotFound, "Record not found"
45
+ end
46
+ end
47
+
48
+ ## Post to the specified object on the collection path
49
+ def post(path)
50
+ Request.new(path.to_s, :post).make
51
+ end
52
+
53
+ ## Return the collection path for this model. Very lazy pluralizion here
54
+ ## at the moment, nothing in Point needs to be pluralized with anything
55
+ ## other than just adding an 's'.
56
+ def collection_path(params = {})
57
+ class_name.downcase + 's'
58
+ end
59
+
60
+ ## Return the member path for the passed ID & attributes
61
+ def member_path(id, params = {})
62
+ [collection_path, id].join('/')
63
+ end
64
+
65
+ ## Return the point class name
66
+ def class_name
67
+ self.name.to_s.split('::').last.downcase
68
+ end
69
+
70
+ private
71
+
72
+ ## Create a new object with the specified attributes and getting and ID.
73
+ ## Returns the newly created object
74
+ def create_object(attributes, objects = [])
75
+ o = self.new
76
+ o.attributes = attributes
77
+ o.id = attributes['id']
78
+ for key, object in objects.select{|k,v| v.kind_of?(Point::Base)}
79
+ o.attributes[key.to_s] = object
80
+ end
81
+ o
82
+ end
83
+ end
84
+
85
+ ## Run a post on the member path. Returns the ouput from the post, false if a conflict or raises
86
+ ## a Point::Error. Optionally, pass a second 'data' parameter to send data to the post action.
87
+ def post(action, data = nil)
88
+ path = self.class.member_path(self.id, default_params) + "/" + action.to_s
89
+ request = Request.new(path, :post)
90
+ request.data = data
91
+ request.make
92
+ end
93
+
94
+ ## Delete this record from the remote service. Returns true or false depending on the success
95
+ ## status of the destruction.
96
+ def destroy
97
+ Request.new(self.class.member_path(self.id, default_params), :delete).make.success?
98
+ end
99
+
100
+ def new_record?
101
+ self.id.nil?
102
+ end
103
+
104
+ def save
105
+ new_record? ? create : update
106
+ end
107
+
108
+ def create
109
+ request = Request.new(self.class.collection_path(default_params), :post)
110
+ request.data = {self.class.class_name.downcase.to_sym => attributes_to_post}
111
+ if request.make && request.success?
112
+ new_record = JSON.parse(request.output)[self.class.class_name]
113
+ self.id = new_record['id']
114
+ true
115
+ else
116
+ populate_errors(request.output)
117
+ false
118
+ end
119
+ end
120
+
121
+ ## Push the updated attributes to the remote. Returns true if the record was saved successfully
122
+ ## other false if not. If not saved successfully, the errors hash will be updated with an array
123
+ ## of all errors with the submission.
124
+ def update
125
+ request = Request.new(self.class.member_path(self.id, default_params), :put)
126
+ request.data = {self.class.class_name.downcase.to_sym => attributes_to_post}
127
+ if request.make && request.success?
128
+ true
129
+ else
130
+ populate_errors(request.output)
131
+ false
132
+ end
133
+ end
134
+
135
+ private
136
+
137
+ ## Populate the errors hash from the given raw JSON output
138
+ def populate_errors(json)
139
+ self.errors = Hash.new
140
+ JSON.parse(json).inject(self.errors) do |r, e|
141
+ r[e.first] = e.last
142
+ r
143
+ end
144
+ end
145
+
146
+ ## An array of params which should always be sent with this instances requests
147
+ def default_params
148
+ Hash.new
149
+ end
150
+
151
+ ## Attributes which can be passed for update & creation
152
+ def attributes_to_post
153
+ self.attributes.inject(Hash.new) do |r,(key,value)|
154
+ r[key] = value if value.is_a?(String) || value.is_a?(Integer) || value.is_a?(Fixnum)
155
+ r
156
+ end
157
+ end
158
+
159
+ end
160
+ end
@@ -0,0 +1,20 @@
1
+ module Point
2
+
3
+ ## Base level error which all other point errors will inherit from. It may also be
4
+ ## invoked for errors which don't directly relate to other errors below.
5
+ class Error < StandardError; end
6
+
7
+ module Errors
8
+
9
+ ## The service is currently unavailable. This may be caused by rate limiting or the API
10
+ ## or the service has been disabled by the system
11
+ class ServiceUnavailable < Error; end
12
+
13
+ ## Access was denied to the remote service
14
+ class AccessDenied < Error; end
15
+
16
+ ## A communication error occured while talking to the Point API
17
+ class CommunicationError < Error; end
18
+
19
+ end
20
+ end
@@ -0,0 +1,63 @@
1
+ module Point
2
+ class Request
3
+
4
+ attr_reader :path, :method
5
+ attr_accessor :data
6
+
7
+ def initialize(path, method = :get)
8
+ @path = path
9
+ @method = method
10
+ end
11
+
12
+ def success?
13
+ @success || false
14
+ end
15
+
16
+ def output
17
+ @output || nil
18
+ end
19
+
20
+ ## Make a request to the Point API using net/http. Data passed can be a hash or a string
21
+ ## Hashes will be converted to JSON before being sent to the remote service.
22
+ def make
23
+ uri = URI.parse([Point.site, @path].join('/'))
24
+ http_request = http_class.new(uri.path)
25
+ http_request.basic_auth(Point.username, Point.apitoken)
26
+ http_request.add_field("Accept", "application/json")
27
+ http_request.add_field("Content-type", "application/json")
28
+
29
+ http = Net::HTTP.new(uri.host, uri.port)
30
+ data = self.data.to_json if self.data.is_a?(Hash) && self.data.respond_to?(:to_json)
31
+ http_result = http.request(http_request, data)
32
+ @output = http_result.body
33
+ @success = case http_result
34
+ when Net::HTTPSuccess
35
+ true
36
+ when Net::HTTPServiceUnavailable
37
+ raise Point::Errors::ServiceUnavailable
38
+ when Net::HTTPForbidden, Net::HTTPUnauthorized
39
+ raise Point::Errors::AccessDenied, "Access Denied for '#{Point.username}'"
40
+ when Net::HTTPNotFound
41
+ raise Point::Errors::CommunicationError, "Not Found at #{uri.to_s}"
42
+ when Net::HTTPClientError
43
+ false
44
+ else
45
+ raise Point::Errors::CommunicationError, http_result.body
46
+ end
47
+ self
48
+ end
49
+
50
+ private
51
+
52
+ def http_class
53
+ case @method
54
+ when :post then Net::HTTP::Post
55
+ when :put then Net::HTTP::Put
56
+ when :delete then Net::HTTP::Delete
57
+ else
58
+ Net::HTTP::Get
59
+ end
60
+ end
61
+
62
+ end
63
+ end
@@ -0,0 +1,24 @@
1
+ module Point
2
+ class Zone < Base
3
+
4
+ def apply!
5
+ post(:apply)
6
+ end
7
+
8
+ def records
9
+ ZoneRecord.find(:all, :zone => self)
10
+ end
11
+
12
+ def record(id)
13
+ ZoneRecord.find(id, :zone => self)
14
+ end
15
+
16
+ def build_record(attributes = {})
17
+ z = ZoneRecord.new
18
+ z.attributes = attributes if attributes.is_a?(Hash)
19
+ z.zone = self
20
+ z
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,23 @@
1
+ module Point
2
+ class ZoneRecord < Base
3
+
4
+ class << self
5
+ def collection_path(params = {})
6
+ "zones/#{params[:zone].id}/records"
7
+ end
8
+
9
+ def member_path(id, params = {})
10
+ "zones/#{params[:zone].id}/records/#{id}"
11
+ end
12
+
13
+ def class_name
14
+ "zone_record"
15
+ end
16
+ end
17
+
18
+ def default_params
19
+ {:zone => self.zone}
20
+ end
21
+
22
+ end
23
+ end
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: point
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Adam Cooke
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-29 00:00:00 +00:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: json
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.1.5
24
+ version:
25
+ description:
26
+ email: adam@atechmedia.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - lib/point/base.rb
35
+ - lib/point/errors.rb
36
+ - lib/point/request.rb
37
+ - lib/point/zone.rb
38
+ - lib/point/zone_record.rb
39
+ - lib/point.rb
40
+ has_rdoc: true
41
+ homepage: http://www.pointhq.com
42
+ licenses: []
43
+
44
+ post_install_message:
45
+ rdoc_options: []
46
+
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ version:
61
+ requirements: []
62
+
63
+ rubyforge_project:
64
+ rubygems_version: 1.3.5
65
+ signing_key:
66
+ specification_version: 3
67
+ summary: API client for the PointHQ DNS Hosting System
68
+ test_files: []
69
+