point 1.0.0

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.
@@ -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
+