ripple-rest 0.0.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. data/README.md +8 -0
  2. data/lib/ripple-rest.rb +4 -8
  3. data/lib/ripple-rest/{schemas/json.rb → generated-schemas.rb} +154 -149
  4. data/lib/ripple-rest/{schemas/payments.rb → helpers.rb} +129 -22
  5. data/lib/ripple-rest/rest-object.rb +191 -0
  6. data/lib/ripple-rest/schemas.rb +82 -0
  7. data/lib/ripple-rest/version.rb +2 -2
  8. metadata +6 -43
  9. data/lib/ripple-rest/schemas/account.rb +0 -84
  10. data/lib/ripple-rest/schemas/account_settings.rb +0 -22
  11. data/lib/ripple-rest/schemas/amount.rb +0 -21
  12. data/lib/ripple-rest/schemas/balance.rb +0 -8
  13. data/lib/ripple-rest/schemas/json/AccountSettings.json +0 -63
  14. data/lib/ripple-rest/schemas/json/Amount.json +0 -28
  15. data/lib/ripple-rest/schemas/json/Balance.json +0 -23
  16. data/lib/ripple-rest/schemas/json/Currency.json +0 -7
  17. data/lib/ripple-rest/schemas/json/FloatString.json +0 -7
  18. data/lib/ripple-rest/schemas/json/Hash128.json +0 -7
  19. data/lib/ripple-rest/schemas/json/Hash256.json +0 -7
  20. data/lib/ripple-rest/schemas/json/Notification.json +0 -58
  21. data/lib/ripple-rest/schemas/json/Order.json +0 -82
  22. data/lib/ripple-rest/schemas/json/Payment.json +0 -98
  23. data/lib/ripple-rest/schemas/json/ResourceId.json +0 -7
  24. data/lib/ripple-rest/schemas/json/RippleAddress.json +0 -7
  25. data/lib/ripple-rest/schemas/json/Timestamp.json +0 -7
  26. data/lib/ripple-rest/schemas/json/Trustline.json +0 -58
  27. data/lib/ripple-rest/schemas/json/UINT32.json +0 -7
  28. data/lib/ripple-rest/schemas/json/URL.json +0 -7
  29. data/lib/ripple-rest/schemas/json/_generate.rb +0 -73
  30. data/lib/ripple-rest/schemas/notifications.rb +0 -19
  31. data/lib/ripple-rest/schemas/trustlines.rb +0 -40
@@ -1,35 +1,103 @@
1
1
  module RippleRest
2
- class Payment
3
- # Gets Account object of this Payment's source account
4
- def account
5
- @account
2
+ class Account
3
+ # Account's Address (rXXXXXX...)
4
+ # @return [String]
5
+ attr_accessor :address
6
+
7
+ # Account's secret
8
+ # @return [String]
9
+ attr_accessor :secret
10
+
11
+ def initialize address, secret = nil
12
+ @address = address
13
+ @secret = secret
6
14
  end
7
15
 
8
- # Sets source account and secret for this Payment
9
- # @param val [Account]
10
- def account= val
11
- @account = val
12
- self.source_account = val.address
16
+ # Get an account's existing balances.
17
+ # This includes XRP balance (which does not include a counterparty) and trustline balances.
18
+ # @return [Array<Balance>]
19
+ # @raise [RippleRestError] if RippleRest server returns an error
20
+ # @raise [ProtocolError] if protocol is wrong or network is down
21
+ def balances
22
+ RippleRest
23
+ .get("v1/accounts/#{@address}/balances")["balances"]
24
+ .map(&Balance.method(:new))
13
25
  end
14
26
 
15
- # Submits a payment
16
- # @return [String] Client resource ID
17
- # @raise [ArgumentError] if secret is missing from the Account object
27
+ # Returns a Trustlines object for this account.
28
+ # @return [Trustlines]
18
29
  # @raise [RippleRestError] if RippleRest server returns an error
19
30
  # @raise [ProtocolError] if protocol is wrong or network is down
20
- def submit
21
- @account.require_secret
22
-
23
- hash = {}
24
- hash["payment"] = self.to_hash
25
- hash["secret"] = @account.secret
26
- hash["client_resource_id"] = client_resource_id = RippleRest.next_uuid
27
-
28
- RippleRest.post("v1/payments", hash)["client_resource_id"]
31
+ def trustlines
32
+ data = RippleRest
33
+ .get("v1/accounts/#{@address}/trustlines")["trustlines"]
34
+ .map(&Trustline.method(:new))
35
+ obj = Trustlines.new data
36
+ obj.account = self
37
+ obj
29
38
  end
30
39
 
40
+ # Returns a AccountSettings object for this account.
41
+ # @return [AccountSettings]
42
+ # @raise [RippleRestError] if RippleRest server returns an error
43
+ # @raise [ProtocolError] if protocol is wrong or network is down
44
+ def settings
45
+ data = RippleRest.get("v1/accounts/#{@address}/settings")["settings"]
46
+ obj = AccountSettings.new data
47
+ obj.account = self
48
+ obj
49
+ end
50
+
51
+ # Returns a Notifications object for this account.
52
+ # @return [Notifications]
53
+ def notifications
54
+ @notifications ||= lambda {
55
+ obj = Notifications.new
56
+ obj.account = self
57
+ obj
58
+ }.call
59
+ end
60
+
61
+ # Returns a Payments object for this account.
62
+ # @return [Payments]
63
+ def payments
64
+ payments ||= lambda {
65
+ obj = Payments.new
66
+ obj.account = self
67
+ obj
68
+ }.call
69
+ end
70
+
71
+ # Returns the address of attribute address.
31
72
  # @return [String]
32
- attr_accessor :client_resource_id
73
+ def to_s
74
+ address
75
+ end
76
+
77
+ # @!group Private APIs
78
+ # @api private
79
+ def require_secret
80
+ raise ArgumentError.new("Secret is required for this operation.") unless secret
81
+ end
82
+ # @!endgroup
83
+ end
84
+
85
+ class Notifications
86
+ # @return [Account]
87
+ attr_accessor :account
88
+
89
+ # Get notifications.
90
+ #
91
+ # Clients using notifications to monitor their account activity should pay particular attention to the `state` and `result` fields. The `state` field will either be `validated` or `failed` and represents the finalized status of that transaction. The `result` field will be `tesSUCCESS` if the `state` was validated. If the transaction failed, `result` will contain the `rippled` or `ripple-lib` error code.
92
+ #
93
+ # Notifications have `next_notification_url` and `previous_notification_url`'s. Account notifications can be polled by continuously following the `next_notification_url`, and handling the resultant notifications, until the `next_notification_url` is an empty string. This means that there are no new notifications but, as soon as there are, querying the same URL that produced this notification in the first place will return the same notification but with the `next_notification_url` set.
94
+ # @raise [RippleRestError] if RippleRest server returns an error
95
+ # @raise [ProtocolError] if protocol is wrong or network is down
96
+ # @return [Notification]
97
+ def [] hash
98
+ Notification.new RippleRest
99
+ .get("v1/accounts/#{account.address}/notifications/#{hash}")["notification"]
100
+ end
33
101
  end
34
102
 
35
103
  class Payments
@@ -103,4 +171,43 @@ module RippleRest
103
171
  end
104
172
  end
105
173
  end
174
+
175
+ class Trustlines
176
+ include Enumerable
177
+
178
+ # @return [Account]
179
+ attr_accessor :account
180
+
181
+ def initialize data
182
+ @data = data
183
+ end
184
+
185
+ # Use with Enumerable
186
+ def each *args, &block
187
+ @data.each *args, &block
188
+ end
189
+
190
+ # Add trustline
191
+ # @param obj [String, Hash] Either a string representation of trustline limit, Hash containing value, currency, counterparty or a string form value/currency/counterparty.
192
+ # @param allow_rippling [Boolean] See [here](https://ripple.com/wiki/No_Ripple) for details
193
+ # @raise [ArgumentError] if secret is missing from the Account object
194
+ # @raise [RippleRestError] if RippleRest server returns an error
195
+ # @raise [ProtocolError] if protocol is wrong or network is down
196
+ def add obj, allow_rippling = true
197
+ raise ArgumentError.new("Account is missing.") unless account
198
+ account.require_secret
199
+
200
+ hash = {}
201
+ hash["allow_rippling"] = allow_rippling
202
+ hash["secret"] = account.secret
203
+
204
+ if obj.is_a? String
205
+ hash["trustline"] = { "limit" => obj }
206
+ else
207
+ hash["trustline"] = obj.to_hash
208
+ end
209
+
210
+ RippleRest.post "v1/accounts/#{account.address}/trustlines", hash
211
+ end
212
+ end
106
213
  end
@@ -0,0 +1,191 @@
1
+ require 'uri'
2
+ require 'time'
3
+
4
+ module RippleRest
5
+ # @api private
6
+ module RestTypeHelper
7
+ # @!visibility private
8
+ # @api private
9
+ def self.exist? key
10
+ @converter ||= {}
11
+ @converter.keys.include? key
12
+ end
13
+
14
+ # @!visibility private
15
+ # @api private
16
+ def self.register key, to, from, check, name = nil
17
+ return key if exist? key
18
+
19
+ @converter ||= {}
20
+ @converter[key] = [to, from, check, name ? name : key.to_s]
21
+
22
+ key
23
+ end
24
+
25
+ # @!visibility private
26
+ # @api private
27
+ def self.register_string key, regexp
28
+ reg = Regexp.new regexp
29
+
30
+ register key,
31
+ RETURN_SELF,
32
+ RETURN_SELF,
33
+ lambda { |x| (x.is_a?(String) && x.match(reg)) },
34
+ "String<#{key}>: #{reg.inspect}"
35
+ end
36
+
37
+ # @!visibility private
38
+ # @api private
39
+ def self.register_array type
40
+ register :"Array<#{type}>",
41
+ lambda { |x| x.map { |i| self.convert_to(type, i) } },
42
+ lambda { |x| x.map { |i| self.convert_from(type, i) } },
43
+ lambda { |x| (x.is_a?(Array) && x.all? {|i| self.convert_check(type, i) }) },
44
+ "Array<#{type}>"
45
+ end
46
+
47
+ # @!visibility private
48
+ # @api private
49
+ def self.register_string_otg regexp
50
+ register_string :"String<#{regexp.inspect}>", regexp
51
+ end
52
+
53
+ # @!visibility private
54
+ # @api private
55
+ def self.register_object key, klass
56
+ register key,
57
+ lambda { |x| x.to_hash },
58
+ lambda { |x| x.is_a?(klass) ? x : klass.new(x) },
59
+ lambda { |x| x.is_a? klass },
60
+ "#{key}"
61
+ end
62
+
63
+ # @!visibility private
64
+ # @api private
65
+ def self.convert_to type, obj
66
+ return nil if obj.nil?
67
+ @converter[type][0].call obj
68
+ end
69
+
70
+ # @!visibility private
71
+ # @api private
72
+ def self.convert_from type, obj
73
+ return nil if obj.nil?
74
+ @converter[type][1].call obj
75
+ end
76
+
77
+ # @!visibility private
78
+ # @api private
79
+ def self.convert_check type, obj
80
+ return true if obj.nil?
81
+ @converter[type][2].call obj
82
+ end
83
+
84
+ # @!visibility private
85
+ # @api private
86
+ def self.convert_raise type, obj
87
+ raise ArgumentError.new "#{obj.inspect} cannot be casted to #{@converter[type][3]}"
88
+ end
89
+
90
+ # @api private
91
+ RETURN_SELF = lambda { |x| x }
92
+
93
+ register :String,
94
+ RETURN_SELF,
95
+ RETURN_SELF,
96
+ lambda { |x| x.is_a?(String) }
97
+
98
+ register :Boolean,
99
+ RETURN_SELF,
100
+ RETURN_SELF,
101
+ lambda { |x| [true, false].include? x }
102
+
103
+ register :FloatString,
104
+ lambda { |x| x.is_a?(BigDecimal) ? x.to_s("F") : BigDecimal.new(x.to_s).to_s("F") },
105
+ lambda { |x| x.is_a?(BigDecimal) ? x : BigDecimal.new(x) },
106
+ lambda { |x| x.is_a?(BigDecimal) || x.respond_to?(:to_f)}
107
+
108
+ register :UINT32,
109
+ lambda { |x| x.to_i.to_s },
110
+ lambda { |x| x.to_i },
111
+ lambda { |x| x.is_a?(Numeric) && x >= 0 && x <= 4294967295 }
112
+
113
+ register :Timestamp,
114
+ lambda { |x| x.iso8601 },
115
+ lambda { |x| x.is_a?(Time) ? x : Time.iso8601(x) },
116
+ lambda { |x| x.is_a?(Time) || x.is_a?(String) }
117
+
118
+ register :URL,
119
+ lambda { |x| x.to_s },
120
+ lambda { |x| URI(x.to_s) },
121
+ lambda { |x| x.is_a?(URI) || x.respond_to?(:to_s) }
122
+ end
123
+
124
+ class RestObject
125
+ # @param data [Hash]
126
+ def initialize data = nil
127
+ data.each do |key, value|
128
+ if @@properties[self.class][key.to_sym]
129
+ self.instance_variable_set :"@#{key}", RestTypeHelper.convert_from(@@properties[self.class][key.to_sym], value)
130
+ else
131
+ warn "Cannot found field `#{key}' in RippleRestObject #{self.class}. The value will leave as-is. However, this will not be serialized to JSON."
132
+ self.instance_variable_set :"@#{key}", value
133
+ end
134
+ end if data
135
+ end
136
+
137
+ # Convert to a hash
138
+ # @return [Hash]
139
+ def to_hash
140
+ result = {}
141
+ @@properties[self.class].each do |key, type|
142
+ value = self.instance_variable_get(:"@#{key}")
143
+ if @@required[self.class][key] && value == nil
144
+ raise ArgumentError.new("Field `#{key}' is required in RippleRestObject #{self.class}.")
145
+ end
146
+ result[key] = RestTypeHelper.convert_to(type, value) if value != nil
147
+ end
148
+
149
+ result
150
+ end
151
+
152
+ # @!visibility protected
153
+ # @api private
154
+ def self.required symbol
155
+ @@required[self][symbol] = true
156
+ end
157
+
158
+ # @!visibility protected
159
+ # @api private
160
+ def self.property symbol, typeobj
161
+ if typeobj.is_a? Symbol
162
+ type = typeobj
163
+ elsif typeobj.is_a?(Array) && typeobj[0] == :String
164
+ type = RestTypeHelper.register_string_otg typeobj[1]
165
+ elsif typeobj.is_a?(Array) && typeobj[0] == :Array
166
+ type = RestTypeHelper.register_array typeobj[1]
167
+ end
168
+
169
+ define_method :"#{symbol}", &lambda { self.instance_variable_get :"@#{symbol}" }
170
+ define_method :"#{symbol}=", &lambda { |value|
171
+ begin
172
+ raise "" unless RestTypeHelper.convert_check(type, value)
173
+ self.instance_variable_set :"@#{symbol}", RestTypeHelper.convert_from(type, value)
174
+ rescue
175
+ RestTypeHelper.convert_raise type, value
176
+ end
177
+ }
178
+
179
+ @@properties[self][symbol] = type
180
+ end
181
+
182
+ @@required ||= Hash.new { |h, k| h[k] = Hash.new }
183
+ @@properties ||= Hash.new { |h, k| h[k] = Hash.new }
184
+ end
185
+
186
+
187
+ class << RestObject
188
+ protected :property
189
+ protected :required
190
+ end
191
+ end
@@ -0,0 +1,82 @@
1
+ module RippleRest
2
+ class AccountSettings
3
+ # @return [Account]
4
+ attr_accessor :account
5
+
6
+ # Save the account settings
7
+ # @raise [ArgumentError] if secret is missing from the Account object
8
+ # @raise [RippleRestError] if RippleRest server returns an error
9
+ # @raise [ProtocolError] if protocol is wrong or network is down
10
+ # @return [void]
11
+ def save
12
+ raise ArgumentError.new("Account is missing.") unless account
13
+
14
+ account.require_secret
15
+
16
+ hash = to_hash
17
+ hash["secret"] = account.secret
18
+
19
+ RippleRest.post "v1/accounts/#{account.address}/settings", hash
20
+ end
21
+ end
22
+
23
+ class Amount
24
+ # @return [String]
25
+ def to_s
26
+ "#{value}+#{currency}#{issuer.to_s.size > 0 ? ("+" + issuer) : ""}"
27
+ end
28
+
29
+ # @param s [String, Amount] an Amount object or a String like "1+XRP" or "1+USD+r..."
30
+ # @return [Amount]
31
+ def self.from_string s
32
+ return s if s.is_a?(Amount)
33
+
34
+ arr = s.split("+")
35
+ Amount.new({
36
+ "value" => arr[0],
37
+ "currency" => arr[1],
38
+ "issuer" => arr[2]
39
+ })
40
+ end
41
+ end
42
+
43
+ class Balance
44
+ # @return [String]
45
+ def inspect
46
+ "#{value.to_s} #{currency}#{counterparty.to_s.size > 0 ? " (#{counterparty})" : ""}"
47
+ end
48
+ end
49
+
50
+ class Payment
51
+ # Gets Account object of this Payment's source account
52
+ def account
53
+ @account
54
+ end
55
+
56
+ # Sets source account and secret for this Payment
57
+ # @param val [Account]
58
+ def account= val
59
+ @account = val
60
+ self.source_account = val.address
61
+ end
62
+
63
+ # Submits a payment
64
+ # @return [String] Client resource ID
65
+ # @raise [ArgumentError] if secret is missing from the Account object
66
+ # @raise [RippleRestError] if RippleRest server returns an error
67
+ # @raise [ProtocolError] if protocol is wrong or network is down
68
+ def submit
69
+ @account.require_secret
70
+
71
+ hash = {}
72
+ hash["payment"] = self.to_hash
73
+ hash["secret"] = @account.secret
74
+ hash["client_resource_id"] = client_resource_id = RippleRest.next_uuid
75
+
76
+ RippleRest.post("v1/payments", hash)["client_resource_id"]
77
+ end
78
+
79
+ # @return [String]
80
+ attr_accessor :client_resource_id
81
+ end
82
+ end
@@ -1,3 +1,3 @@
1
1
  module RippleRest
2
- VERSION = "0.0.2"
3
- end
2
+ VERSION = "1.0.0"
3
+ end