investolink 1.0.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/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rest-client', '~> 1.4'
4
+ gem 'multi_json', '~> 1.1'
5
+ gem "activesupport", "~> 3.0"
6
+
7
+ # Specify your gem's dependencies in investolink.gemspec
8
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Crowdnetic
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,18 @@
1
+ # Investolink
2
+
3
+
4
+ ## Installation
5
+
6
+ Add this line to your application's Gemfile:
7
+
8
+ gem 'crowdnetic'
9
+
10
+ And then execute:
11
+
12
+ $ bundle
13
+
14
+ Or install it yourself as:
15
+
16
+ $ gem install crowdnetic
17
+
18
+
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.unshift(File.join(File.dirname(__FILE__), 'lib'))
3
+
4
+ require 'investolink/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.authors = ["Sri Goteti"]
8
+ gem.email = ["sri@crowdnetic.com"]
9
+ gem.description = %q{"Crowdnetic provides transparency for the private and crowdfunded securities marketplace.See http://www.crowdnetic.com for more details."}
10
+ gem.summary = %q{"Crowdnetic Ruby bindings for InvestoLink API"}
11
+ gem.homepage = "http://www.crowdnetic.com"
12
+
13
+ gem.files = `git ls-files`.split($\)
14
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
15
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
16
+ gem.name = "investolink"
17
+ gem.require_paths = ["lib"]
18
+ gem.version = Investolink::VERSION
19
+ end
@@ -0,0 +1,5 @@
1
+ module Investolink
2
+ class Asset < Resource
3
+ include Investolink::Operations::Update
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Investolink
2
+ class Donation < Resource
3
+ include Investolink::Operations::Update
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ module Investolink
2
+ class APIConnectionError < InvestolinkError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Investolink
2
+ class APIError < InvestolinkError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Investolink
2
+ class AuthenticationError < InvestolinkError
3
+ end
4
+ end
@@ -0,0 +1,10 @@
1
+ module Investolink
2
+ class InvalidRequestError < InvestolinkError
3
+ attr_accessor :param
4
+
5
+ def initialize(message, param, http_status=nil, http_body=nil, json_body=nil)
6
+ super(message, http_status, http_body, json_body)
7
+ @param = param
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,20 @@
1
+ module Investolink
2
+ class InvestolinkError < StandardError
3
+ attr_reader :message
4
+ attr_reader :http_status
5
+ attr_reader :http_body
6
+ attr_reader :json_body
7
+
8
+ def initialize(message=nil, http_status=nil, http_body=nil, json_body=nil)
9
+ @message = message
10
+ @http_status = http_status
11
+ @http_body = http_body
12
+ @json_body = json_body
13
+ end
14
+
15
+ def to_s
16
+ status_string = @http_status.nil? ? "" : "(Status #{@http_status}) "
17
+ "#{status_string}#{@message}"
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,5 @@
1
+ module Investolink
2
+ class Fundallocation < Resource
3
+ include Investolink::Operations::Update
4
+ end
5
+ end
@@ -0,0 +1,148 @@
1
+ module Investolink
2
+ class InvestolinkObject
3
+ include Enumerable
4
+
5
+ attr_accessor :api_key, :api_token
6
+ @@permanent_attributes = Set.new([:api_key, :api_token])
7
+
8
+ # The default :id method is deprecated and isn't useful to us
9
+ if method_defined?(:id)
10
+ undef :id
11
+ end
12
+
13
+ def initialize(id=nil, api_key=nil, api_token=nil)
14
+ @api_key = api_key
15
+ @api_token = api_token
16
+ @values = {}
17
+
18
+ @unsaved_values = Set.new
19
+ @transient_values = Set.new
20
+ self.id = id if id
21
+ end
22
+
23
+ def self.construct_from(values, api_key=nil, api_token=nil)
24
+ obj = self.new(values[:id], api_key, api_token)
25
+ obj.refresh_from(values, api_key, api_token)
26
+ obj
27
+ end
28
+
29
+ def to_s(*args)
30
+ Investolink::JSON.dump(@values, :pretty => true)
31
+ end
32
+
33
+ def inspect()
34
+ id_string = (self.respond_to?(:id) && !self.id.nil?) ? " id=#{self.id}" : ""
35
+ "#<#{self.class}:0x#{self.object_id.to_s(16)}#{id_string}> JSON: " + Investolink::JSON.dump(@values, :pretty => true)
36
+ end
37
+
38
+ def refresh_from(values, api_key, api_token, partial=false)
39
+ @api_key = api_key
40
+ @api_token = api_token
41
+
42
+ removed = partial ? Set.new : Set.new(@values.keys - values.keys)
43
+ added = Set.new(values.keys - @values.keys)
44
+
45
+ instance_eval do
46
+ remove_accessors(removed)
47
+ add_accessors(added)
48
+ end
49
+ removed.each do |k|
50
+ @values.delete(k)
51
+ @transient_values.add(k)
52
+ @unsaved_values.delete(k)
53
+ end
54
+ values.each do |k, v|
55
+ @values[k] = Util.convert_to_investolink_object(v, api_key, api_token)
56
+ @transient_values.delete(k)
57
+ @unsaved_values.delete(k)
58
+ end
59
+ end
60
+
61
+ def [](k)
62
+ k = k.to_sym if k.kind_of?(String)
63
+ @values[k]
64
+ end
65
+
66
+ def []=(k, v)
67
+ send(:"#{k}=", v)
68
+ end
69
+
70
+ def keys
71
+ @values.keys
72
+ end
73
+
74
+ def values
75
+ @values.values
76
+ end
77
+
78
+ def to_json(*a)
79
+ Investolink::JSON.dump(@values)
80
+ end
81
+
82
+ def as_json(*a)
83
+ @values.as_json(*a)
84
+ end
85
+
86
+ def to_hash
87
+ @values
88
+ end
89
+
90
+ def each(&blk)
91
+ @values.each(&blk)
92
+ end
93
+
94
+ protected
95
+
96
+ def metaclass
97
+ class << self; self; end
98
+ end
99
+
100
+ def remove_accessors(keys)
101
+ metaclass.instance_eval do
102
+ keys.each do |k|
103
+ next if @@permanent_attributes.include?(k)
104
+ k_eq = :"#{k}="
105
+ remove_method(k) if method_defined?(k)
106
+ remove_method(k_eq) if method_defined?(k_eq)
107
+ end
108
+ end
109
+ end
110
+
111
+ def add_accessors(keys)
112
+ metaclass.instance_eval do
113
+ keys.each do |k|
114
+ next if @@permanent_attributes.include?(k)
115
+ k_eq = :"#{k}="
116
+ define_method(k) { @values[k] }
117
+ define_method(k_eq) do |v|
118
+ @values[k] = v
119
+ @unsaved_values.add(k)
120
+ end
121
+ end
122
+ end
123
+ end
124
+
125
+ def method_missing(name, *args)
126
+ # TODO: only allow setting in updateable classes.
127
+ if name.to_s.end_with?('=')
128
+ attr = name.to_s[0...-1].to_sym
129
+ @values[attr] = args[0]
130
+ @unsaved_values.add(attr)
131
+ add_accessors([attr])
132
+ return
133
+ else
134
+ return @values[name] if @values.has_key?(name)
135
+ end
136
+
137
+ begin
138
+ super
139
+ rescue NoMethodError => e
140
+ if @transient_values.include?(name)
141
+ raise NoMethodError.new(e.message + ". HINT: The '#{name}' attribute was set in the past, however. It was then wiped when refreshing the object with the result returned by Crowdnetic's API, probably as a result of a save(). The attributes currently available on this object are: #{@values.keys.join(', ')}")
142
+ else
143
+ raise
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,27 @@
1
+ module Investolink
2
+ class Issue < Resource
3
+ include Investolink::Operations::Create
4
+ include Investolink::Operations::Update
5
+
6
+ def transactions(params={})
7
+ response, api_key, api_token = Investolink.request(:get, transactions_url, @api_key, @api_token, params)
8
+ Util.convert_to_investolink_object(response, api_key, api_token)
9
+ end
10
+
11
+ def new_transaction(params)
12
+ response, api_key, api_token = Investolink.request(:post, new_transaction_url(id), @api_key, @api_token, params)
13
+ Util.convert_to_investolink_object(response, api_key, api_token)
14
+ end
15
+
16
+ private
17
+
18
+ def transactions_url
19
+ resource_url + '/transactions'
20
+ end
21
+
22
+ def new_transaction_url(id)
23
+ "/issues/#{CGI.escape(id)}/new-transaction"
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,5 @@
1
+ module Investolink
2
+ class IssueTransaction < Resource
3
+ include Investolink::Operations::Update
4
+ end
5
+ end
@@ -0,0 +1,29 @@
1
+ module Investolink
2
+ class Issuer < Resource
3
+
4
+ def ownerships(params={})
5
+ response, api_key, api_token = Investolink.request(:get, ownership_url, @api_key, @api_token, params)
6
+ Util.convert_to_investolink_object(response, api_key, api_token)
7
+ end
8
+
9
+ def new_owner(params={})
10
+ response, api_key, api_token = Investolink.request(:post, new_ownership_url(id), @api_key, @api_token, params)
11
+ Util.convert_to_investolink_object(response, api_key, api_token)
12
+ end
13
+
14
+ private
15
+
16
+ def issues_url
17
+ resource_url + '/issues'
18
+ end
19
+
20
+ def ownership_url
21
+ resource_url + '/ownership'
22
+ end
23
+
24
+ def new_ownership_url(id)
25
+ "/issuers/#{CGI.escape(id)}/new-owner"
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,5 @@
1
+ module Investolink
2
+ class IssuerOwnership < Resource
3
+ include Investolink::Operations::Update
4
+ end
5
+ end
@@ -0,0 +1,21 @@
1
+ module Investolink
2
+ module JSON
3
+ if MultiJson.respond_to?(:dump)
4
+ def self.dump(*args)
5
+ MultiJson.dump(*args)
6
+ end
7
+
8
+ def self.load(*args)
9
+ MultiJson.load(*args)
10
+ end
11
+ else
12
+ def self.dump(*args)
13
+ MultiJson.encode(*args)
14
+ end
15
+
16
+ def self.load(*args)
17
+ MultiJson.decode(*args)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,16 @@
1
+ module Investolink
2
+ module Operations
3
+ module Create
4
+ module ClassMethods
5
+ def create(params={}, api_key=nil, api_token=nil)
6
+ response, api_key, api_token = Investolink.request(:post, self.resource_url + '/new', api_key, api_token, params)
7
+ Util.convert_to_investolink_object(response, api_key, api_token)
8
+ end
9
+ end
10
+
11
+ def self.included(base)
12
+ base.extend(ClassMethods)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module Investolink
2
+ module Operations
3
+ module List
4
+ module ClassMethods
5
+ def all(filters={}, api_key=nil, api_token=nil)
6
+ response, api_key, api_token = Investolink.request(:get, resource_url, api_key, api_token, filters)
7
+ Util.convert_to_investolink_object(response, api_key, api_token)
8
+ end
9
+ end
10
+
11
+ def self.included(base)
12
+ base.extend(ClassMethods)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ module Investolink
2
+ module Operations
3
+ module Update
4
+ def save
5
+ if @unsaved_values.length > 0
6
+ values = {}
7
+ @unsaved_values.each { |k| values[k] = @values[k] }
8
+ response, api_key = Investolink.request(:post, self.resource_url + '/update', @api_key, @api_token, values)
9
+ refresh_from(response, api_key, api_token)
10
+ end
11
+ self
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,98 @@
1
+ module Investolink
2
+ class Project < Resource
3
+ include Investolink::Operations::Create
4
+ include Investolink::Operations::Update
5
+
6
+ def rewards(params={})
7
+ response, api_key, api_token = Investolink.request(:get, rewards_url, @api_key, @api_token, params)
8
+ Util.convert_to_investolink_object(response, api_key, api_token)
9
+ end
10
+
11
+ def new_reward(params)
12
+ response, api_key, api_token = Investolink.request(:post, new_reward_url(id), @api_key, @api_token, params)
13
+ Util.convert_to_investolink_object(response, api_key, api_token)
14
+ end
15
+
16
+ def assets(params={})
17
+ response, api_key, api_token = Investolink.request(:get, assets_url, @api_key, @api_token, params)
18
+ Util.convert_to_investolink_object(response, api_key, api_token)
19
+ end
20
+
21
+ def new_asset(params)
22
+ response, api_key, api_token = Investolink.request(:post, new_asset_url(id), @api_key, @api_token, params)
23
+ Util.convert_to_investolink_object(response, api_key, api_token)
24
+ end
25
+
26
+ def sociallinks(params={})
27
+ response, api_key, api_token = Investolink.request(:get, sociallinks_url, @api_key, @api_token, params)
28
+ Util.convert_to_investolink_object(response, api_key, api_token)
29
+ end
30
+
31
+ def new_sociallink(params)
32
+ response, api_key, api_token = Investolink.request(:post, new_sociallink_url(id), @api_key, @api_token, params)
33
+ Util.convert_to_investolink_object(response, api_key, api_token)
34
+ end
35
+
36
+ def fundallocations(params={})
37
+ response, api_key, api_token = Investolink.request(:get, fundallocations_url, @api_key, @api_token, params)
38
+ Util.convert_to_investolink_object(response, api_key, api_token)
39
+ end
40
+
41
+ def new_fundallocation(params)
42
+ response, api_key, api_token = Investolink.request(:post, new_fundallocation_url(id), @api_key, @api_token, params)
43
+ Util.convert_to_investolink_object(response, api_key, api_token)
44
+ end
45
+
46
+ def donations(params={})
47
+ response, api_key, api_token = Investolink.request(:get, donations_url, @api_key, @api_token, params)
48
+ Util.convert_to_investolink_object(response, api_key, api_token)
49
+ end
50
+
51
+ def new_donation(params)
52
+ response, api_key, api_token = Investolink.request(:post, new_donation_url(id), @api_key, @api_token, params)
53
+ Util.convert_to_investolink_object(response, api_key, api_token)
54
+ end
55
+
56
+ private
57
+
58
+ def rewards_url
59
+ resource_url + '/rewards'
60
+ end
61
+
62
+ def new_reward_url(id)
63
+ "/projects/#{CGI.escape(id)}/new-reward"
64
+ end
65
+
66
+ def assets_url
67
+ resource_url + '/assets'
68
+ end
69
+
70
+ def new_asset_url(id)
71
+ "/projects/#{CGI.escape(id)}/new-asset"
72
+ end
73
+
74
+ def sociallinks_url
75
+ resource_url + '/sociallinks'
76
+ end
77
+
78
+ def new_sociallink_url(id)
79
+ "/projects/#{CGI.escape(id)}/new-sociallink"
80
+ end
81
+
82
+ def fundallocations_url
83
+ resource_url + '/fundallocations'
84
+ end
85
+
86
+ def new_fundallocation_url(id)
87
+ "/projects/#{CGI.escape(id)}/new-fundallocation"
88
+ end
89
+
90
+ def donations_url
91
+ resource_url + '/donations'
92
+ end
93
+
94
+ def new_donation_url(id)
95
+ "/projects/#{CGI.escape(id)}/new-donation"
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,31 @@
1
+ module Investolink
2
+ class Resource < InvestolinkObject
3
+ def self.resource_url
4
+ if self == Resource
5
+ raise NotImplementedError.new('Resource is an abstract class. You should perform actions on its subclasses (Issuer, Issue, etc.)')
6
+ end
7
+ shortname = self.name.split('::')[-1]
8
+ shortname = Util.to_underscore(shortname.to_s)
9
+ "/#{CGI.escape(shortname.downcase)}s"
10
+ end
11
+
12
+ def resource_url
13
+ unless id = self['id']
14
+ raise InvalidRequestError.new("Could not determine which URL to request: #{self.class} instance has invalid ID: #{id.inspect}", 'id')
15
+ end
16
+ "#{self.class.resource_url}/#{CGI.escape(id.to_s)}"
17
+ end
18
+
19
+ def refresh
20
+ response, api_key, api_token = Investolink.request(:get, resource_url, @api_key, @api_token)
21
+ refresh_from(response, api_key, api_token)
22
+ self
23
+ end
24
+
25
+ def self.retrieve(id, api_key=nil, api_token=nil)
26
+ instance = self.new(id, api_key, api_token)
27
+ instance.refresh
28
+ instance
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,5 @@
1
+ module Investolink
2
+ class Reward < Resource
3
+ include Investolink::Operations::Update
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Investolink
2
+ class Sociallink < Resource
3
+ include Investolink::Operations::Update
4
+ end
5
+ end
@@ -0,0 +1,169 @@
1
+ module Investolink
2
+ class Subscriber < Resource
3
+
4
+ def self.search(params={})
5
+ response, api_key, api_token = Investolink.request(:get, search_url, @api_key, @api_token, params)
6
+ Util.convert_to_investolink_object(response, api_key, api_token)
7
+ end
8
+
9
+ def self.issue(id)
10
+ response, api_key, api_token = Investolink.request(:get, issue_url(id), @api_key, @api_token)
11
+ Util.convert_to_investolink_object(response, api_key, api_token)
12
+ end
13
+
14
+ def self.issuer(id)
15
+ response, api_key, api_token = Investolink.request(:get, issuer_url(id), @api_key, @api_token)
16
+ Util.convert_to_investolink_object(response, api_key, api_token)
17
+ end
18
+
19
+ def self.transaction(id)
20
+ response, api_key, api_token = Investolink.request(:get, transaction_url(id), @api_key, @api_token)
21
+ Util.convert_to_investolink_object(response, api_key, api_token)
22
+ end
23
+
24
+ def self.owner(id)
25
+ response, api_key, api_token = Investolink.request(:get, owner_url(id), @api_key, @api_token)
26
+ Util.convert_to_investolink_object(response, api_key, api_token)
27
+ end
28
+
29
+ def self.issue_transactions(id)
30
+ response, api_key, api_token = Investolink.request(:get, issue_transactions_url(id), @api_key, @api_token)
31
+ Util.convert_to_investolink_object(response, api_key, api_token)
32
+ end
33
+
34
+ def self.issuer_owners(id)
35
+ response, api_key, api_token = Investolink.request(:get, issuer_owners_url(id), @api_key, @api_token)
36
+ Util.convert_to_investolink_object(response, api_key, api_token)
37
+ end
38
+
39
+ def self.project(id)
40
+ response, api_key, api_token = Investolink.request(:get, project_url(id), @api_key, @api_token)
41
+ Util.convert_to_investolink_object(response, api_key, api_token)
42
+ end
43
+
44
+ def self.reward(id)
45
+ response, api_key, api_token = Investolink.request(:get, reward_url(id), @api_key, @api_token)
46
+ Util.convert_to_investolink_object(response, api_key, api_token)
47
+ end
48
+
49
+ def self.rewards(id)
50
+ response, api_key, api_token = Investolink.request(:get, rewards_url(id), @api_key, @api_token)
51
+ Util.convert_to_investolink_object(response, api_key, api_token)
52
+ end
53
+
54
+ def self.donation(id)
55
+ response, api_key, api_token = Investolink.request(:get, donation_url(id), @api_key, @api_token)
56
+ Util.convert_to_investolink_object(response, api_key, api_token)
57
+ end
58
+
59
+ def self.donations(id)
60
+ response, api_key, api_token = Investolink.request(:get, donations_url(id), @api_key, @api_token)
61
+ Util.convert_to_investolink_object(response, api_key, api_token)
62
+ end
63
+
64
+ def self.asset(id)
65
+ response, api_key, api_token = Investolink.request(:get, asset_url(id), @api_key, @api_token)
66
+ Util.convert_to_investolink_object(response, api_key, api_token)
67
+ end
68
+
69
+ def self.assets(id)
70
+ response, api_key, api_token = Investolink.request(:get, assets_url(id), @api_key, @api_token)
71
+ Util.convert_to_investolink_object(response, api_key, api_token)
72
+ end
73
+
74
+ def self.fundallocation(id)
75
+ response, api_key, api_token = Investolink.request(:get, fundallocation_url(id), @api_key, @api_token)
76
+ Util.convert_to_investolink_object(response, api_key, api_token)
77
+ end
78
+
79
+ def self.fundallocations(id)
80
+ response, api_key, api_token = Investolink.request(:get, fundallocations_url(id), @api_key, @api_token)
81
+ Util.convert_to_investolink_object(response, api_key, api_token)
82
+ end
83
+
84
+ def self.sociallink(id)
85
+ response, api_key, api_token = Investolink.request(:get, sociallink_url(id), @api_key, @api_token)
86
+ Util.convert_to_investolink_object(response, api_key, api_token)
87
+ end
88
+
89
+ def self.sociallinks(id)
90
+ response, api_key, api_token = Investolink.request(:get, sociallinks_url(id), @api_key, @api_token)
91
+ Util.convert_to_investolink_object(response, api_key, api_token)
92
+ end
93
+
94
+ private
95
+
96
+ def self.search_url
97
+ "/feed/search"
98
+ end
99
+
100
+ def self.issue_url(id)
101
+ "/feed/issues/#{CGI.escape(id)}"
102
+ end
103
+
104
+ def self.issuer_url(id)
105
+ "/feed/issuer/#{id}"
106
+ end
107
+
108
+ def self.issue_transactions_url(id)
109
+ "/feed/issues/#{id}/transactions"
110
+ end
111
+
112
+ def self.issuer_owners_url(id)
113
+ "/feed/issuer/#{id}/ownership"
114
+ end
115
+
116
+ def self.transaction_url(id)
117
+ "/feed/issue-transactions/#{id}"
118
+ end
119
+
120
+ def self.owner_url(id)
121
+ "/feed/issuer-ownerships/#{id}"
122
+ end
123
+
124
+ def self.project_url(id)
125
+ "/feed/projects/#{CGI.escape(id)}"
126
+ end
127
+
128
+ def self.reward_url(id)
129
+ "/feed/rewards/#{id}"
130
+ end
131
+
132
+ def self.rewards_url(id)
133
+ "/feed/issues/#{id}/rewards"
134
+ end
135
+
136
+ def self.donation_url(id)
137
+ "/feed/donations/#{id}"
138
+ end
139
+
140
+ def self.donations_url(id)
141
+ "/feed/issues/#{id}/donations"
142
+ end
143
+
144
+ def self.asset_url(id)
145
+ "/feed/assets/#{id}"
146
+ end
147
+
148
+ def self.assets_url(id)
149
+ "/feed/issues/#{id}/assets"
150
+ end
151
+
152
+ def self.fundallocation_url(id)
153
+ "/feed/fundallocations/#{id}"
154
+ end
155
+
156
+ def self.fundallocations_url(id)
157
+ "/feed/issues/#{id}/fundallocations"
158
+ end
159
+
160
+ def self.sociallink_url(id)
161
+ "/feed/sociallinks/#{id}"
162
+ end
163
+
164
+ def self.sociallinks_url(id)
165
+ "/feed/issues/#{id}/sociallinks"
166
+ end
167
+
168
+ end
169
+ end
@@ -0,0 +1,110 @@
1
+ module Investolink
2
+ module Util
3
+ def self.objects_to_ids(h)
4
+ case h
5
+ when Resource
6
+ h.id
7
+ when Hash
8
+ res = {}
9
+ h.each { |k, v| res[k] = objects_to_ids(v) unless v.nil? }
10
+ res
11
+ when Array
12
+ h.map { |v| objects_to_ids(v) }
13
+ else
14
+ h
15
+ end
16
+ end
17
+
18
+ def self.convert_to_investolink_object(resp, api_key, api_token)
19
+ types = {
20
+ 'issuer' => Issuer,
21
+ 'issue' => Issue,
22
+ 'issue-transaction' => IssueTransaction,
23
+ 'issuer-ownership' => IssuerOwnership,
24
+ 'project' => Project,
25
+ 'reward' => Reward,
26
+ 'donation' => Donation,
27
+ 'asset' => Asset,
28
+ 'fundallocation' => Fundallocation,
29
+ 'sociallink' => Sociallink,
30
+ }
31
+ case resp
32
+ when Array
33
+ resp.map { |i| convert_to_investolink_object(i, api_key, api_token) }
34
+ when Hash
35
+ # Try converting to a known object class. If none available, fall back to generic Resource
36
+ if klass_name = resp[:object]
37
+ klass = types[klass_name]
38
+ end
39
+ klass ||= InvestolinkObject
40
+ klass.construct_from(resp, api_key, api_token)
41
+ else
42
+ resp
43
+ end
44
+ end
45
+
46
+ def self.file_readable(file)
47
+ begin
48
+ File.open(file) { |f| }
49
+ rescue
50
+ false
51
+ else
52
+ true
53
+ end
54
+ end
55
+
56
+ def self.symbolize_names(object)
57
+ case object
58
+ when Hash
59
+ new = {}
60
+ object.each do |key, value|
61
+ key = (key.to_sym rescue key) || key
62
+ new[key] = symbolize_names(value)
63
+ end
64
+ new
65
+ when Array
66
+ object.map { |value| symbolize_names(value) }
67
+ else
68
+ object
69
+ end
70
+ end
71
+
72
+ def self.encode_key(key)
73
+ URI.escape(key.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
74
+ end
75
+
76
+ def self.flatten_params(params, parent_key=nil)
77
+ result = []
78
+ params.each do |key, value|
79
+ calculated_key = parent_key ? "#{parent_key}[#{encode_key(key)}]" : encode_key(key)
80
+ if value.is_a?(Hash)
81
+ result += flatten_params(value, calculated_key)
82
+ elsif value.is_a?(Array)
83
+ result += flatten_params_array(value, calculated_key)
84
+ else
85
+ result << [calculated_key, value]
86
+ end
87
+ end
88
+ result
89
+ end
90
+
91
+ def self.flatten_params_array(value, calculated_key)
92
+ result = []
93
+ value.each do |elem|
94
+ if elem.is_a?(Hash)
95
+ result += flatten_params(elem, calculated_key)
96
+ elsif elem.is_a?(Array)
97
+ result += flatten_params_array(elem, calculated_key)
98
+ else
99
+ result << ["#{calculated_key}[]", elem]
100
+ end
101
+ end
102
+ result
103
+ end
104
+
105
+ def self.to_underscore(text)
106
+ text.gsub(/(.)([A-Z])/,'\1-\2').downcase
107
+ end
108
+
109
+ end
110
+ end
@@ -0,0 +1,3 @@
1
+ module Investolink
2
+ VERSION = "1.0.2"
3
+ end
@@ -0,0 +1,240 @@
1
+ require 'cgi'
2
+ require 'set'
3
+ require 'rubygems'
4
+ require 'openssl'
5
+
6
+ gem 'rest-client', '~> 1.4'
7
+ require 'rest_client'
8
+ require 'multi_json'
9
+
10
+ #Version
11
+ require "investolink/version"
12
+
13
+ #API Operations
14
+ require "investolink/operations/create"
15
+ #require "investolink/operations/list"
16
+ require "investolink/operations/update"
17
+
18
+ #Resources
19
+ require "investolink/util"
20
+ require "investolink/json"
21
+ require "investolink/investolink_object"
22
+ require "investolink/resource"
23
+ require "investolink/issuer"
24
+ require "investolink/issue"
25
+ require "investolink/issue_transaction"
26
+ require "investolink/issuer_ownership"
27
+ require "investolink/project"
28
+ require "investolink/asset"
29
+ require "investolink/donation"
30
+ require "investolink/sociallink"
31
+ require "investolink/fundallocation"
32
+ require "investolink/reward"
33
+ require "investolink/subscriber"
34
+
35
+ #Errors
36
+ require "investolink/errors/investolink_error"
37
+ require "investolink/errors/api_connection_error"
38
+ require "investolink/errors/api_error"
39
+ require "investolink/errors/authentication_error"
40
+ require "investolink/errors/invalid_request_error"
41
+
42
+
43
+ module Investolink
44
+ @@api_key = nil
45
+ @@api_token = nil
46
+ @@api_base = "https://api.crowdnetic.com/v1"
47
+
48
+ def self.api_url(url='')
49
+ @@api_base + url
50
+ end
51
+
52
+ def self.api_key=(api_key)
53
+ @@api_key = api_key
54
+ end
55
+
56
+ def self.api_key
57
+ @@api_key
58
+ end
59
+
60
+ def self.api_base=(api_base)
61
+ @@api_base = api_base
62
+ end
63
+
64
+ def self.api_base
65
+ @@api_base
66
+ end
67
+
68
+ def self.api_token=(api_token)
69
+ @@api_token = api_token
70
+ end
71
+
72
+ def self.api_token
73
+ @@api_token
74
+ end
75
+
76
+ def self.request(method, url, api_key, api_token, params=nil, headers={})
77
+ api_key ||= @@api_key
78
+ api_token ||= @@api_token
79
+ raise AuthenticationError.new('No API key provided. (HINT: set your API key using "Investolink.api_key = <API-KEY> and Investolink.api_token = <API-TOKEN>". You can generate API keys from the Crowdnetic web interface. See http://www.crowdnetic.com for details, or email support-api@crowdnetic.com if you have any questions.)') unless api_key
80
+
81
+ =begin
82
+ if !verify_ssl_certs
83
+ unless @no_verify
84
+ $stderr.puts "WARNING: Running without SSL cert verification. Execute 'Investolink.verify_ssl_certs = true' to enable verification."
85
+ @no_verify = true
86
+ end
87
+ ssl_opts = { :verify_ssl => false }
88
+ elsif !Util.file_readable(@@ssl_bundle_path)
89
+ unless @no_bundle
90
+ $stderr.puts "WARNING: Running without SSL cert verification because #{@@ssl_bundle_path} isn't readable"
91
+ @no_bundle = true
92
+ end
93
+ ssl_opts = { :verify_ssl => false }
94
+ else
95
+ ssl_opts = {
96
+ :verify_ssl => OpenSSL::SSL::VERIFY_PEER,
97
+ :ssl_ca_file => @@ssl_bundle_path
98
+ }
99
+ end
100
+ =end
101
+ ssl_opts = {}
102
+
103
+ uname = (@@uname ||= RUBY_PLATFORM =~ /linux|darwin/i ? `uname -a 2>/dev/null`.strip : nil)
104
+ lang_version = "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE})"
105
+ ua = {
106
+ :bindings_version => Investolink::VERSION,
107
+ :lang => 'ruby',
108
+ :lang_version => lang_version,
109
+ :platform => RUBY_PLATFORM,
110
+ :publisher => 'investolink',
111
+ :uname => uname
112
+ }
113
+
114
+ params = Util.objects_to_ids(params)
115
+ url = self.api_url(url) + ".json"
116
+ case method.to_s.downcase.to_sym
117
+ when :get, :head, :delete
118
+ # Make params into GET parameters
119
+ if params && params.count
120
+ query_string = Util.flatten_params(params).collect{|p| "#{p[0]}=#{p[1]}"}.join('&')
121
+ url += "?#{query_string}"
122
+ end
123
+ payload = nil
124
+ else
125
+ payload = params
126
+ end
127
+
128
+ begin
129
+ headers = { :x_investolink_client_user_agent => Investolink::JSON.dump(ua) }.merge(headers)
130
+ rescue => e
131
+ headers = {
132
+ :x_investolink_client_raw_user_agent => ua.inspect,
133
+ :error => "#{e} (#{e.class})"
134
+ }.merge(headers)
135
+ end
136
+
137
+ headers = {
138
+ :user_agent => "Investolink/v1 RubyBindings/#{Investolink::VERSION}",
139
+ :x_api_key => "#{api_key}",
140
+ :x_api_token => "#{api_token}"
141
+ }.merge(headers)
142
+ opts = {
143
+ :method => method,
144
+ :url => url,
145
+ :headers => headers,
146
+ :open_timeout => 30,
147
+ :payload => payload,
148
+ :timeout => 80
149
+ }.merge(ssl_opts)
150
+
151
+ begin
152
+ response = execute_request(opts)
153
+ rescue SocketError => e
154
+ self.handle_restclient_error(e)
155
+ rescue NoMethodError => e
156
+ # Work around RestClient bug
157
+ if e.error_message =~ /\WRequestFailed\W/
158
+ e = APIConnectionError.new('Unexpected HTTP response code')
159
+ self.handle_restclient_error(e)
160
+ else
161
+ raise
162
+ end
163
+ rescue RestClient::ExceptionWithResponse => e
164
+ if rcode = e.http_code and rbody = e.http_body
165
+ self.handle_api_error(rcode, rbody)
166
+ else
167
+ self.handle_restclient_error(e)
168
+ end
169
+ rescue RestClient::Exception, Errno::ECONNREFUSED => e
170
+ self.handle_restclient_error(e)
171
+ end
172
+
173
+ rbody = response.body
174
+ rcode = response.code
175
+ begin
176
+ # Would use :symbolize_names => true, but apparently there is
177
+ # some library out there that makes symbolize_names not work.
178
+ resp = Investolink::JSON.load(rbody)
179
+ rescue MultiJson::DecodeError
180
+ raise APIError.new("Invalid response object from API: #{rbody.inspect} (HTTP response code was #{rcode})", rcode, rbody)
181
+ end
182
+
183
+ resp = Util.symbolize_names(resp)
184
+ [resp, api_key, api_token]
185
+ end
186
+
187
+ private
188
+
189
+ def self.execute_request(opts)
190
+ RestClient::Request.execute(opts)
191
+ end
192
+
193
+ def self.handle_api_error(rcode, rbody)
194
+ begin
195
+ error_obj = Investolink::JSON.load(rbody)
196
+ error_obj = Util.symbolize_names(error_obj)
197
+ error = error_obj[:error] or raise InvestolinkError.new # escape from parsing
198
+ rescue MultiJson::DecodeError, InvestolinkError
199
+ raise APIError.new("Invalid response object from API: #{rbody.inspect} (HTTP response code was #{rcode})", rcode, rbody)
200
+ end
201
+
202
+ case rcode
203
+ when 400, 404 then
204
+ raise invalid_request_error(error, rcode, rbody, error_obj)
205
+ when 401
206
+ raise authentication_error(error, rcode, rbody, error_obj)
207
+ when 402
208
+ else
209
+ raise api_error(error, rcode, rbody, error_obj)
210
+ end
211
+ end
212
+
213
+ def self.invalid_request_error(error, rcode, rbody, error_obj)
214
+ InvalidRequestError.new(error[:error_message], error[:param], rcode, rbody, error_obj)
215
+ end
216
+
217
+ def self.authentication_error(error, rcode, rbody, error_obj)
218
+ AuthenticationError.new(error[:error_message], rcode, rbody, error_obj)
219
+ end
220
+
221
+ def self.api_error(error, rcode, rbody, error_obj)
222
+ APIError.new(error[:error_message], rcode, rbody, error_obj)
223
+ end
224
+
225
+ def self.handle_restclient_error(e)
226
+ case e
227
+ when RestClient::ServerBrokeConnection, RestClient::RequestTimeout
228
+ message = "Could not connect to Crowdnetic (#{@@api_base}). Please check your internet connection and try again. If this problem persists, please let us know at support-api@crowdnetic.com."
229
+ when RestClient::SSLCertificateNotVerified
230
+ message = "Could not verify Crowdnetic's SSL certificate. Please make sure that your network is not intercepting certificates. (Try going to https://api.crowdnetic.com/v1 in your browser.) If this problem persists, let us know at support-api@crowdnetic.com."
231
+ when SocketError
232
+ message = "Unexpected error communicating when trying to connect to Crowdnetic. HINT: You may be seeing this message because your DNS is not working. To check, try running 'host Crowdnetic.com' from the command line."
233
+ else
234
+ message = "Unexpected error communicating with Crowdnetic. If this problem persists, let us know at support-api@crowdnetic.com."
235
+ end
236
+ message += "\n\n(Network error: #{e.message})"
237
+ raise APIConnectionError.new(message)
238
+ end
239
+
240
+ end
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: investolink
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Sri Goteti
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-07-25 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: ! '"Crowdnetic provides transparency for the private and crowdfunded
15
+ securities marketplace.See http://www.crowdnetic.com for more details."'
16
+ email:
17
+ - sri@crowdnetic.com
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - .gitignore
23
+ - Gemfile
24
+ - LICENSE
25
+ - README.md
26
+ - Rakefile
27
+ - investolink.gemspec
28
+ - lib/investolink.rb
29
+ - lib/investolink/asset.rb
30
+ - lib/investolink/donation.rb
31
+ - lib/investolink/errors/api_connection_error.rb
32
+ - lib/investolink/errors/api_error.rb
33
+ - lib/investolink/errors/authentication_error.rb
34
+ - lib/investolink/errors/invalid_request_error.rb
35
+ - lib/investolink/errors/investolink_error.rb
36
+ - lib/investolink/fundallocation.rb
37
+ - lib/investolink/investolink_object.rb
38
+ - lib/investolink/issue.rb
39
+ - lib/investolink/issue_transaction.rb
40
+ - lib/investolink/issuer.rb
41
+ - lib/investolink/issuer_ownership.rb
42
+ - lib/investolink/json.rb
43
+ - lib/investolink/operations/create.rb
44
+ - lib/investolink/operations/list.rb
45
+ - lib/investolink/operations/update.rb
46
+ - lib/investolink/project.rb
47
+ - lib/investolink/resource.rb
48
+ - lib/investolink/reward.rb
49
+ - lib/investolink/sociallink.rb
50
+ - lib/investolink/subscriber.rb
51
+ - lib/investolink/util.rb
52
+ - lib/investolink/version.rb
53
+ homepage: http://www.crowdnetic.com
54
+ licenses: []
55
+ post_install_message:
56
+ rdoc_options: []
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ! '>='
63
+ - !ruby/object:Gem::Version
64
+ version: '0'
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ requirements: []
72
+ rubyforge_project:
73
+ rubygems_version: 1.8.24
74
+ signing_key:
75
+ specification_version: 3
76
+ summary: ! '"Crowdnetic Ruby bindings for InvestoLink API"'
77
+ test_files: []