metamolecular-chemcaster 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +35 -0
- data/Rakefile +8 -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
- data/lib/chemcaster.rb +15 -0
- metadata +76 -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
@@ -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
|
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'
|
metadata
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: metamolecular-chemcaster
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.5
|
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
|
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.4
|
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
|
+
licenses:
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options: []
|
53
|
+
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: "0"
|
61
|
+
version:
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: "0"
|
67
|
+
version:
|
68
|
+
requirements: []
|
69
|
+
|
70
|
+
rubyforge_project:
|
71
|
+
rubygems_version: 1.3.5
|
72
|
+
signing_key:
|
73
|
+
specification_version: 2
|
74
|
+
summary: A hypertext-driven Ruby client for the Chemcaster cheminformatics Web services platform. End.
|
75
|
+
test_files: []
|
76
|
+
|