metamolecular-chemcaster-ruby 0.1.2
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.
- data/README.rdoc +35 -0
- data/Rakefile +8 -0
- data/lib/chemcaster.rb +15 -0
- data/lib/chemcaster/error.rb +36 -0
- data/lib/chemcaster/image.rb +6 -0
- data/lib/chemcaster/index.rb +31 -0
- data/lib/chemcaster/item.rb +24 -0
- data/lib/chemcaster/link.rb +89 -0
- data/lib/chemcaster/media_type.rb +27 -0
- data/lib/chemcaster/query.rb +6 -0
- data/lib/chemcaster/registry.rb +8 -0
- data/lib/chemcaster/representation.rb +66 -0
- data/lib/chemcaster/service.rb +41 -0
- data/lib/chemcaster/structure.rb +6 -0
- metadata +75 -0
data/README.rdoc
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
= Chemcaster Ruby API
|
|
2
|
+
|
|
3
|
+
This is the Ruby interface for the Chemcaster[http://chemcaster.com] RESTful Web
|
|
4
|
+
API. It consists of basic functionality needed to create
|
|
5
|
+
applications using chemical structure registration, storage, imaging, and
|
|
6
|
+
search.
|
|
7
|
+
|
|
8
|
+
== Example Use
|
|
9
|
+
|
|
10
|
+
=== Connecting to the Service
|
|
11
|
+
|
|
12
|
+
require 'lib/chemcaster'
|
|
13
|
+
include Chemcaster
|
|
14
|
+
|
|
15
|
+
service = Service.connect 'username', 'password'
|
|
16
|
+
|
|
17
|
+
=== Loading a Registry
|
|
18
|
+
|
|
19
|
+
require 'lib/chemcaster'
|
|
20
|
+
include Chemcaster
|
|
21
|
+
|
|
22
|
+
service = Service.connect 'username', 'password'
|
|
23
|
+
registries = service.registries
|
|
24
|
+
registries.size # => 3
|
|
25
|
+
registry = registries[0]
|
|
26
|
+
|
|
27
|
+
=== Creating a Registry
|
|
28
|
+
|
|
29
|
+
require 'lib/chemcaster'
|
|
30
|
+
include Chemcaster
|
|
31
|
+
|
|
32
|
+
service = Service.connect 'username', 'password'
|
|
33
|
+
registries = service.registries
|
|
34
|
+
|
|
35
|
+
registries.create :name => 'CarboBlocks, Inc.'
|
data/Rakefile
ADDED
data/lib/chemcaster.rb
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + "/chemcaster/service"
|
|
2
|
+
require File.dirname(__FILE__) + '/chemcaster/service'
|
|
3
|
+
require File.dirname(__FILE__) + '/chemcaster/registry'
|
|
4
|
+
require File.dirname(__FILE__) + '/chemcaster/structure'
|
|
5
|
+
require File.dirname(__FILE__) + '/chemcaster/query'
|
|
6
|
+
require File.dirname(__FILE__) + '/chemcaster/image'
|
|
7
|
+
require File.dirname(__FILE__) + '/chemcaster/link'
|
|
8
|
+
require File.dirname(__FILE__) + '/chemcaster/index'
|
|
9
|
+
require File.dirname(__FILE__) + '/chemcaster/item'
|
|
10
|
+
require File.dirname(__FILE__) + '/chemcaster/representation'
|
|
11
|
+
require File.dirname(__FILE__) + '/chemcaster/media_type'
|
|
12
|
+
require File.dirname(__FILE__) + '/chemcaster/error'
|
|
13
|
+
|
|
14
|
+
require 'rubygems'
|
|
15
|
+
require 'json'
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module Chemcaster
|
|
2
|
+
class Error < RuntimeError; end
|
|
3
|
+
class LinkNotDefined < Error; end
|
|
4
|
+
class HTTPError < Error
|
|
5
|
+
attr_accessor :response
|
|
6
|
+
def initialize response
|
|
7
|
+
@response = response
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def to_s
|
|
11
|
+
"received response code #{@response.code} with message:\n\n#{parse_errors}"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
protected
|
|
15
|
+
|
|
16
|
+
def parse_errors
|
|
17
|
+
errors = nil
|
|
18
|
+
message = ""
|
|
19
|
+
begin
|
|
20
|
+
errors = JSON.parse response.body
|
|
21
|
+
rescue
|
|
22
|
+
return response.body
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
errors.each do |error|
|
|
26
|
+
if error['field']
|
|
27
|
+
message << "- field '#{error['field']}' #{error['text']}\n"
|
|
28
|
+
else
|
|
29
|
+
message << "- #{error['text']}\n"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
message
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/../chemcaster/representation'
|
|
2
|
+
|
|
3
|
+
module Chemcaster
|
|
4
|
+
class Index < Representation
|
|
5
|
+
attr_accessor :item_links#, :items
|
|
6
|
+
resources :parent
|
|
7
|
+
|
|
8
|
+
def create representation_attributes
|
|
9
|
+
@create_link.post representation_attributes
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def size
|
|
13
|
+
@item_links.size
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def [](index)
|
|
17
|
+
@item_links[index].get
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
protected
|
|
21
|
+
|
|
22
|
+
def load_hash atts
|
|
23
|
+
super
|
|
24
|
+
|
|
25
|
+
@create_link = Link.new atts['create']
|
|
26
|
+
@item_links = atts['items'].inject([]) do |result, atts|
|
|
27
|
+
result << Link.new(atts)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/../chemcaster/representation'
|
|
2
|
+
|
|
3
|
+
module Chemcaster
|
|
4
|
+
class Item < Representation
|
|
5
|
+
resources :index
|
|
6
|
+
|
|
7
|
+
def update representation_attributes
|
|
8
|
+
@update_link.put representation_attributes
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def destroy
|
|
12
|
+
@destroy_link.delete
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
protected
|
|
16
|
+
|
|
17
|
+
def load_hash atts
|
|
18
|
+
super
|
|
19
|
+
|
|
20
|
+
@update_link = Link.new atts['update']
|
|
21
|
+
@destroy_link = Link.new atts['destroy']
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
require 'net/http'
|
|
2
|
+
require 'net/https'
|
|
3
|
+
|
|
4
|
+
module Chemcaster
|
|
5
|
+
class Link
|
|
6
|
+
def initialize atts=nil
|
|
7
|
+
if atts
|
|
8
|
+
@uri = URI.parse(atts['uri']) if atts['uri']
|
|
9
|
+
@media_type = atts['media_type']
|
|
10
|
+
@media_class = MediaType.representation(@media_type) if @media_type
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def get
|
|
15
|
+
do_http 'get'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def put attributes
|
|
19
|
+
do_http 'put', attributes
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def post attributes
|
|
23
|
+
do_http 'post', attributes
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def delete
|
|
27
|
+
do_http 'delete'
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def do_http method, representation=nil
|
|
33
|
+
validate
|
|
34
|
+
request = request_for_method method, representation
|
|
35
|
+
response = send_request request
|
|
36
|
+
|
|
37
|
+
raise(HTTPError, response) unless response.code.to_i < 300
|
|
38
|
+
@media_class.new self, decode(response.body)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def send_request request
|
|
42
|
+
http = Net::HTTP.new(@uri.host, @uri.port)
|
|
43
|
+
http.use_ssl = (@uri.scheme == 'https')
|
|
44
|
+
|
|
45
|
+
if File.exists? Service.root_ca
|
|
46
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
|
47
|
+
http.ca_path = Service.root_ca
|
|
48
|
+
else
|
|
49
|
+
message =
|
|
50
|
+
"net/http couldn't locate this system's root SSL certificate files."+
|
|
51
|
+
"On Debian Linux systems, these files are located at /etc/ssl/certs "+
|
|
52
|
+
"(this library's default). For more information, see:\n\n"+
|
|
53
|
+
"http://codeidol.com/other/rubyckbk/Internet-Services/Making-an-HTTPS-Web-Request\n"+
|
|
54
|
+
"http://redcorundum.blogspot.com/2008/03/ssl-certificates-and-nethttps.html\n"+
|
|
55
|
+
"http://notetoself.vrensk.com/2008/09/verified-https-in-ruby\n"
|
|
56
|
+
raise(message)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
http.request(request)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def request_for_method method, attributes=nil
|
|
63
|
+
request = case method
|
|
64
|
+
when "get" then Net::HTTP::Get.new(@uri.path)
|
|
65
|
+
when "put" then Net::HTTP::Put.new(@uri.path)
|
|
66
|
+
when "post" then Net::HTTP::Post.new(@uri.path)
|
|
67
|
+
when "delete" then Net::HTTP::Delete.new(@uri.path)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
request['accept'] = @media_type
|
|
71
|
+
request.basic_auth Service.username, Service.password
|
|
72
|
+
|
|
73
|
+
if attributes
|
|
74
|
+
request.body = {MediaType.hash_key(@media_type) => attributes}.to_json
|
|
75
|
+
request.content_type = @media_type
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
request
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def validate
|
|
82
|
+
raise LinkNotDefined unless @uri && @media_class
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def decode response
|
|
86
|
+
JSON.parse response
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Chemcaster
|
|
2
|
+
class MediaType
|
|
3
|
+
def self.representation name
|
|
4
|
+
name.match(/application\/vnd\.com\.chemcaster\.(.*)\+json/)
|
|
5
|
+
raise "No such media type: #{name}" unless klass = $1
|
|
6
|
+
|
|
7
|
+
begin
|
|
8
|
+
Object.const_get(klass)
|
|
9
|
+
rescue
|
|
10
|
+
raise "No such class: #{klass}"
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.hash_key full_mime_type_name
|
|
15
|
+
full_mime_type_name.match(/application\/vnd\.com\.chemcaster\.(.*)\+json/)
|
|
16
|
+
raise "No such media type: #{full_mime_type_name}" unless key = $1
|
|
17
|
+
|
|
18
|
+
begin
|
|
19
|
+
Object.const_get(key)
|
|
20
|
+
rescue
|
|
21
|
+
raise "No such class: #{key}"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
key.downcase
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
module Chemcaster
|
|
2
|
+
class Representation
|
|
3
|
+
# class instance variables - see: http://martinfowler.com/bliki/ClassInstanceVariable.html
|
|
4
|
+
class << self; attr_accessor :resource_ids; end
|
|
5
|
+
class << self; attr_accessor :attribute_ids; end
|
|
6
|
+
|
|
7
|
+
attr_accessor :attributes
|
|
8
|
+
attr_accessor :link
|
|
9
|
+
|
|
10
|
+
def initialize link, raw
|
|
11
|
+
@link = link
|
|
12
|
+
@attributes = {}
|
|
13
|
+
load_hash raw
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.attributes *atts
|
|
17
|
+
self.attribute_ids ||= []
|
|
18
|
+
atts.each do |m|
|
|
19
|
+
self.attribute_ids << m.to_s
|
|
20
|
+
define_method(m) do
|
|
21
|
+
attributes[m.to_s]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
define_method("#{m}=") do |val|
|
|
25
|
+
attributes.merge!({m.to_s => val})
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.resources *res
|
|
31
|
+
self.resource_ids ||= self.superclass.resource_ids || []
|
|
32
|
+
res.each do |id|
|
|
33
|
+
self.resource_ids << id
|
|
34
|
+
define_method(id) do
|
|
35
|
+
instance_variable_get("@#{id}_link").send('get')
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def to_json
|
|
41
|
+
JSON({attributes_name => @attributes})
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def attributes_name
|
|
45
|
+
self.class.to_s.gsub(/Chemcaster::/, '').downcase
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
protected
|
|
49
|
+
|
|
50
|
+
def load_hash hash
|
|
51
|
+
self.class.attribute_ids ||= []
|
|
52
|
+
if hash[name = attributes_name]
|
|
53
|
+
hash[name].each do |attribute|
|
|
54
|
+
if self.class.attribute_ids.member? attribute[0]
|
|
55
|
+
attributes[attribute[0]] = attribute[1]
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
self.class.resource_ids ||= []
|
|
61
|
+
self.class.resource_ids.each do |resource_id|
|
|
62
|
+
instance_variable_set("@#{resource_id}_link".to_sym, Link.new(hash[resource_id.to_s]))
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/../chemcaster/representation'
|
|
2
|
+
|
|
3
|
+
module Chemcaster
|
|
4
|
+
class Service < Representation
|
|
5
|
+
attr_accessor :registries_link
|
|
6
|
+
|
|
7
|
+
# Ruby SSL needs to be told the location of the system's SSL CA files.
|
|
8
|
+
# On Debian Linux systems, these files are located at /etc/ssl/certs,
|
|
9
|
+
# which is this library's default. For more information, see:
|
|
10
|
+
#
|
|
11
|
+
# http://codeidol.com/other/rubyckbk/Internet-Services/Making-an-HTTPS-Web-Request
|
|
12
|
+
# http://redcorundum.blogspot.com/2008/03/ssl-certificates-and-nethttps.html
|
|
13
|
+
# http://notetoself.vrensk.com/2008/09/verified-https-in-ruby
|
|
14
|
+
|
|
15
|
+
@@root_ca = nil; def self.root_ca; @@root_ca; end
|
|
16
|
+
@@username = nil; def self.username; @@username; end
|
|
17
|
+
@@password = nil; def self.password; @@password; end
|
|
18
|
+
|
|
19
|
+
def self.connect username, password, options = {}
|
|
20
|
+
@@username = username; @@password = password
|
|
21
|
+
|
|
22
|
+
@@root_ca = options[:root_ca] || '/etc/ssl/certs'
|
|
23
|
+
uri = options[:uri] || 'https://chemcaster.com/rest'
|
|
24
|
+
|
|
25
|
+
service_link = Link.new 'uri' => uri,
|
|
26
|
+
'media_type' => 'application/vnd.com.chemcaster.Service+json', 'name' => 'root'
|
|
27
|
+
service_link.get
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def registries
|
|
31
|
+
@registries_link.get
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
protected
|
|
35
|
+
|
|
36
|
+
def load_hash hash
|
|
37
|
+
super
|
|
38
|
+
@registries_link = Link.new hash['registries']
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: metamolecular-chemcaster-ruby
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.2
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Richard Apodaca
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
|
|
12
|
+
date: 2009-08-17 00:00:00 -07:00
|
|
13
|
+
default_executable:
|
|
14
|
+
dependencies:
|
|
15
|
+
- !ruby/object:Gem::Dependency
|
|
16
|
+
name: json_pure
|
|
17
|
+
type: :runtime
|
|
18
|
+
version_requirement:
|
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
20
|
+
requirements:
|
|
21
|
+
- - ">="
|
|
22
|
+
- !ruby/object:Gem::Version
|
|
23
|
+
version: "0"
|
|
24
|
+
version:
|
|
25
|
+
description: A hypertext-driven Ruby client for the Chemcaster cheminformatics Web services platform.
|
|
26
|
+
email: info@metamolecular.com
|
|
27
|
+
executables: []
|
|
28
|
+
|
|
29
|
+
extensions: []
|
|
30
|
+
|
|
31
|
+
extra_rdoc_files: []
|
|
32
|
+
|
|
33
|
+
files:
|
|
34
|
+
- README.rdoc
|
|
35
|
+
- Rakefile
|
|
36
|
+
- lib/chemcaster.rb
|
|
37
|
+
- lib/chemcaster/error.rb
|
|
38
|
+
- lib/chemcaster/image.rb
|
|
39
|
+
- lib/chemcaster/index.rb
|
|
40
|
+
- lib/chemcaster/item.rb
|
|
41
|
+
- lib/chemcaster/link.rb
|
|
42
|
+
- lib/chemcaster/media_type.rb
|
|
43
|
+
- lib/chemcaster/query.rb
|
|
44
|
+
- lib/chemcaster/registry.rb
|
|
45
|
+
- lib/chemcaster/representation.rb
|
|
46
|
+
- lib/chemcaster/service.rb
|
|
47
|
+
- lib/chemcaster/structure.rb
|
|
48
|
+
has_rdoc: false
|
|
49
|
+
homepage: http://chemcaster.com
|
|
50
|
+
post_install_message:
|
|
51
|
+
rdoc_options: []
|
|
52
|
+
|
|
53
|
+
require_paths:
|
|
54
|
+
- lib
|
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
56
|
+
requirements:
|
|
57
|
+
- - ">="
|
|
58
|
+
- !ruby/object:Gem::Version
|
|
59
|
+
version: "0"
|
|
60
|
+
version:
|
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
62
|
+
requirements:
|
|
63
|
+
- - ">="
|
|
64
|
+
- !ruby/object:Gem::Version
|
|
65
|
+
version: "0"
|
|
66
|
+
version:
|
|
67
|
+
requirements: []
|
|
68
|
+
|
|
69
|
+
rubyforge_project:
|
|
70
|
+
rubygems_version: 1.2.0
|
|
71
|
+
signing_key:
|
|
72
|
+
specification_version: 2
|
|
73
|
+
summary: A hypertext-driven Ruby client for the Chemcaster cheminformatics Web services platform. End.
|
|
74
|
+
test_files: []
|
|
75
|
+
|