unchained 0.0.1 → 0.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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.md +20 -0
  3. data/README.md +38 -0
  4. data/lib/unchained/client.rb +4 -0
  5. data/lib/unchained/client/archetypes.rb +5 -6
  6. data/lib/unchained/client/attributes.rb +35 -0
  7. data/lib/unchained/client/factions.rb +5 -6
  8. data/lib/unchained/client/mixins/resource.rb +110 -16
  9. data/lib/unchained/client/motd.rb +19 -0
  10. data/lib/unchained/client/patcher.rb +11 -13
  11. data/lib/unchained/client/races.rb +5 -6
  12. data/lib/unchained/client/servers.rb +11 -10
  13. data/lib/unchained/error.rb +2 -0
  14. data/lib/unchained/request.rb +5 -1
  15. data/lib/unchained/version.rb +1 -1
  16. data/test/_fixtures/vcr_cassettes/archetypes.yml +51 -0
  17. data/test/_fixtures/vcr_cassettes/attribute_offsets.yml +36 -0
  18. data/test/_fixtures/vcr_cassettes/attributes.yml +100 -0
  19. data/test/_fixtures/vcr_cassettes/factions.yml +45 -0
  20. data/test/_fixtures/vcr_cassettes/motd.yml +36 -0
  21. data/test/_fixtures/vcr_cassettes/patcher_alerts.yml +36 -0
  22. data/test/_fixtures/vcr_cassettes/patcher_hero_contents.yml +104 -0
  23. data/test/_fixtures/vcr_cassettes/races.yml +38 -0
  24. data/test/_fixtures/vcr_cassettes/servers.yml +36 -0
  25. data/test/test_helper.rb +7 -0
  26. data/test/unchained/client/archetypes_test.rb +27 -0
  27. data/test/unchained/client/attributes_test.rb +29 -0
  28. data/test/unchained/client/factions_test.rb +20 -0
  29. data/test/unchained/client/mixins/resource_test.rb +38 -0
  30. data/test/unchained/client/motd_test.rb +23 -0
  31. data/test/unchained/client/patcher_test.rb +29 -0
  32. data/test/unchained/client/races_test.rb +20 -0
  33. data/test/unchained/client/servers_test.rb +20 -0
  34. data/test/unchained/client_test.rb +0 -5
  35. data/unchained.gemspec +4 -2
  36. metadata +66 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d440ea525f7c18793f4604906a9c1eb098e70b87
4
- data.tar.gz: 1d5c9f43267ca976c652ffb615a8d12d5e315a5b
3
+ metadata.gz: 8a4a2a58f8403c47f9d8f1f45cef8df674462f7f
4
+ data.tar.gz: eecb1fc22ce12a1150efdfb27f3ce83df34cfe18
5
5
  SHA512:
6
- metadata.gz: 1acaf1d610b637280ddf66f456b54e70acf1833307840c0f1142e3d83c6f1e97c8165fc3210841bcd22cf2b1308feed77eedb8d96ce1766de99a8d251a6cb002
7
- data.tar.gz: ef53adfdcc531a92902ac9913bcb24599edfdaaa8c245884226eb26dd0f146056777d068fb6f8b4bc160be49ec85d55df760004df4aeea067a45af26f9e85c10
6
+ metadata.gz: 4473fade28915ab541388879834f05d92c7bca0694d5eb3d6a12d9d0f74e2c98d0fd1b408a08ec56125b5ecdb667a4f2c3fc11e2145a9653c9cf6b1fee548d9f
7
+ data.tar.gz: 4889219e809cf2a40f5985c8e8fd7aa8f46d9476118ccf5f42d0624b2fe1f30fadeea69b8e1913aaa5bb2f636c1ff375bdcc815a9f1a4b69557536eeff52af4e
data/LICENSE.md CHANGED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2016 Andrew Thorp
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -0,0 +1,38 @@
1
+ ### Unchained
2
+
3
+ A ruby client library for the Camelot Unchained API.
4
+
5
+ You can view the API documentation at http://api.camelotunchained.com/
6
+
7
+ ### Usage
8
+
9
+ First, install the gem:
10
+
11
+ ```ruby
12
+ gem install unchained
13
+ ```
14
+
15
+ Alternatively, add the gem to your Gemfile:
16
+
17
+ ```ruby
18
+ gem 'unchained'
19
+ ```
20
+
21
+ Once you have the gem installed, you can use it to interact with the Camelot
22
+ Unchained API:
23
+
24
+ ```ruby
25
+ [1] pry(main)> client = Unchained::Client.new;
26
+ [2] pry(main)> client.servers.first
27
+ => #<Unchained::Client::Servers::Server:0x007fa0b94c7258 @access_level=6, @channel_id=4, @host="wyrmlingprep.camelotunchained.com", @name="WyrmlingPrep", @player_maximum=1000, @shard_id=1>
28
+ ```
29
+
30
+ ### TODO
31
+
32
+ - Tests
33
+ - Implement `loginToken` endpoints
34
+
35
+ ### License
36
+
37
+ View the [License](LICENSE.md)
38
+
@@ -4,7 +4,9 @@ require_relative 'request'
4
4
  # RESOURCES
5
5
  require_relative 'client/mixins/resource'
6
6
  require_relative 'client/archetypes'
7
+ require_relative 'client/attributes'
7
8
  require_relative 'client/factions'
9
+ require_relative 'client/motd'
8
10
  require_relative 'client/races'
9
11
  require_relative 'client/patcher'
10
12
  require_relative 'client/servers'
@@ -28,7 +30,9 @@ module Unchained
28
30
 
29
31
  # RESOURCES
30
32
  include Unchained::Client::Archetypes
33
+ include Unchained::Client::Attributes
31
34
  include Unchained::Client::Factions
35
+ include Unchained::Client::MOTD
32
36
  include Unchained::Client::Races
33
37
  include Unchained::Client::Patcher
34
38
  include Unchained::Client::Servers
@@ -4,12 +4,11 @@ module Unchained
4
4
 
5
5
  class Archetype
6
6
  include Unchained::Client::Mixins::Resource
7
- resource({
8
- :description => 'description',
9
- :faction => 'faction',
10
- :id => 'id',
11
- :name => 'name',
12
- })
7
+
8
+ attribute :description, String
9
+ attribute :faction, Integer
10
+ attribute :id, Integer
11
+ attribute :name, String
13
12
  end
14
13
 
15
14
  def archetypes(opts={})
@@ -0,0 +1,35 @@
1
+ module Unchained
2
+ class Client
3
+ module Attributes
4
+
5
+ class AttributeInfo
6
+ include Unchained::Client::Mixins::Resource
7
+
8
+ attribute :base_value, Float, json: 'baseValue'
9
+ attribute :derived_from, String, json: 'derivedFrom'
10
+ attribute :description, String
11
+ attribute :max_or_multipler, Float, json: 'maxOrMultipler'
12
+ attribute :name, String
13
+ attribute :type, Integer
14
+ attribute :units, String
15
+ end
16
+
17
+ class AttributeOffset
18
+ include Unchained::Client::Mixins::Resource
19
+
20
+ attribute :race, Integer
21
+ attribute :gender, Integer
22
+ attribute :offsets, Hash, json: 'attributeOffsets'
23
+ end
24
+
25
+ def attributes(shard, opts={})
26
+ get_resources("#{base_url}/gamedata/attributes/#{shard}", AttributeInfo, opts)
27
+ end
28
+
29
+ def attribute_offsets(shard, opts={})
30
+ get_resources("#{base_url}/gamedata/attributeoffsets/#{shard}", AttributeOffset, opts)
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -4,12 +4,11 @@ module Unchained
4
4
 
5
5
  class Faction
6
6
  include Unchained::Client::Mixins::Resource
7
- resource({
8
- :description => 'description',
9
- :id => 'id',
10
- :name => 'name',
11
- :short_name => 'shortName',
12
- })
7
+
8
+ attribute :description, String
9
+ attribute :id, Integer
10
+ attribute :name, String
11
+ attribute :short_name, String, json: 'shortName'
13
12
  end
14
13
 
15
14
  def factions(opts={})
@@ -1,41 +1,135 @@
1
1
  module Unchained
2
2
  class Client
3
3
  module Mixins
4
+
5
+ # The Resource mixin gives you access to a DSL that lets you define what
6
+ # the class should look like in the JSON response.
7
+ #
8
+ # Usage:
9
+ #
10
+ # class Guild
11
+ # include Unchained::Client::Mixins::Resource
12
+ #
13
+ # attribute :id, String
14
+ # attribute :name, String
15
+ # attribute :members, Integer, json: 'numberOfMembers'
16
+ # end
17
+ #
18
+
4
19
  module Resource
20
+
21
+ # An `Attribute` is what `attribute` creates.
22
+ class Attribute
23
+ attr_reader :name
24
+ attr_reader :type
25
+ attr_reader :opts
26
+
27
+ def initialize(name, type, opts)
28
+ @name = name
29
+ @type = type
30
+ @opts = opts
31
+ end
32
+
33
+ # The field that maps to this attribute in the JSON.
34
+ #
35
+ # Usage:
36
+ #
37
+ # # json_field will return 'FOO'
38
+ # attribute :foo, json: 'FOO'
39
+ #
40
+ # # json_field will return 'foo_bar'
41
+ # attribute :foo_bar
42
+ #
43
+ def json_field
44
+ @opts.fetch(:json, @name.to_s)
45
+ end
46
+
47
+ # Whether or not to allow nil, defaults to false.
48
+ def allow_nil?
49
+ @opts.fetch(:allow_nil, false)
50
+ end
51
+ end
52
+
5
53
  def self.included(base)
6
54
  base.extend ClassMethods
7
55
  end
8
56
 
57
+ # Mostly just a helper method that you can override if you
58
+ # want to.
9
59
  def to_s
10
- attributes = self.class::JSON_MAP.map{|k,_| "#{k}=#{self.send(k)}"}.join(" ")
11
- "[#{self.class_name}] #{attributes}"
12
- end
60
+ attrs = self.class.attributes.map do |attr|
61
+ "#{attr.name}=#{self.send(attr.name)}"
62
+ end.join(', ')
13
63
 
14
- # Lurk, is there not a better way to do this?
15
- def class_name
16
- self.class.name.split('::').last
64
+ "[#{self.class.name.split('::').last}] #{attrs}"
17
65
  end
18
66
 
19
67
  module ClassMethods
20
- JSON_MAP = {}
68
+ attr_reader :attributes
21
69
 
22
- def resource(json_map)
70
+ def attribute(name, type, opts={})
23
71
  instance_eval do
24
- const_set("JSON_MAP", json_map)
72
+ attr_accessor name
25
73
  end
26
74
 
27
- class_eval do
28
- attr_accessor(*json_map.keys)
75
+ @attributes ||= []
76
+ @attributes << Attribute.new(name, type, opts)
77
+ end
78
+
79
+ # This is a pretty naive implementation of parsing JSON. It will
80
+ # loop through all of `@attributes` to find the right one, then do
81
+ # some very minimal validation, before setting the attribute on the
82
+ # instance.
83
+ #
84
+ # Returns an instance of the class that uses this mixin.
85
+ def from_json(json)
86
+ res = self.new
87
+
88
+ json.each do |k, v|
89
+ # TODO: Better way to do this?
90
+ attr = @attributes.find{|a| a.json_field == k.to_s}
91
+ raise InvalidAttribute.new(
92
+ "`#{self.name.split('::').last}` did not define a `#{k}`."
93
+ ) if attr.nil?
94
+
95
+ # TODO: Better way to do this?
96
+ case attr.type.to_s
97
+ when Integer.to_s
98
+ maybe_raise_invalid_value(attr, k, v) unless v.is_a?(Fixnum)
99
+ value = v.to_i
100
+ when Float.to_s
101
+ maybe_raise_invalid_value(attr, k, v) unless v.is_a?(Float)
102
+ value = v.to_f
103
+ when String.to_s
104
+ maybe_raise_invalid_value(attr, k, v) unless v.is_a?(String)
105
+ value = v
106
+ when Hash.to_s
107
+ maybe_raise_invalid_value(attr, k, v) unless v.is_a?(Hash)
108
+ value = v
109
+ end
110
+
111
+ res.send("#{attr.name}=", value)
29
112
  end
113
+
114
+ res
30
115
  end
31
116
 
32
- def decode_result(json)
33
- instance = self.new
34
- self::JSON_MAP.each do |k,v|
35
- instance.send("#{k}=", json[v])
117
+ private
118
+
119
+ def maybe_raise_invalid_value(attribute, key, value)
120
+ if value.nil?
121
+ return if attribute.allow_nil?
122
+
123
+ raise InvalidValue.new(
124
+ "`#{attribute.name}` is not allowed to be nil.",
125
+ )
36
126
  end
37
- instance
127
+
128
+ raise InvalidValue.new(
129
+ "Expected #{attribute.type}, got #{value.class}. `#{key}` (#{value})."
130
+ )
38
131
  end
132
+
39
133
  end
40
134
  end
41
135
  end
@@ -0,0 +1,19 @@
1
+ module Unchained
2
+ class Client
3
+ module MOTD
4
+
5
+ class Message
6
+ include Unchained::Client::Mixins::Resource
7
+
8
+ attribute :id, String
9
+ attribute :message, String
10
+ attribute :duration, Integer
11
+ end
12
+
13
+ def motd(opts={})
14
+ get_resource("#{base_url}/messageoftheday", Message, opts)
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -4,23 +4,21 @@ module Unchained
4
4
 
5
5
  class HeroContent
6
6
  include Unchained::Client::Mixins::Resource
7
- resource({
8
- :id => 'id',
9
- :content => 'content',
10
- :priority => 'priority',
11
- :start => 'utcDateStart',
12
- :end => 'utcDateEnd',
13
- })
7
+
8
+ attribute :id, String
9
+ attribute :content, String
10
+ attribute :priority, Integer
11
+ attribute :start, String, json: 'utcDateStart'
12
+ attribute :end, String, json: 'utcDateEnd'
14
13
  end
15
14
 
16
15
  class Alert
17
16
  include Unchained::Client::Mixins::Resource
18
- resource({
19
- :id => 'id',
20
- :message => 'message',
21
- :start => 'utcDateStart',
22
- :end => 'utcDateEnd',
23
- })
17
+
18
+ attribute :id, String
19
+ attribute :message, String
20
+ attribute :start, String, json: 'utcDateStart'
21
+ attribute :end, String, json: 'utcDateEnd'
24
22
  end
25
23
 
26
24
  def patcher_hero_contents(opts={})
@@ -4,12 +4,11 @@ module Unchained
4
4
 
5
5
  class Race
6
6
  include Unchained::Client::Mixins::Resource
7
- resource({
8
- :description => 'description',
9
- :faction => 'faction',
10
- :id => 'id',
11
- :name => 'name',
12
- })
7
+
8
+ attribute :description, String
9
+ attribute :faction, Integer
10
+ attribute :id, Integer
11
+ attribute :name, String
13
12
  end
14
13
 
15
14
  def races(opts={})
@@ -4,18 +4,19 @@ module Unchained
4
4
 
5
5
  class Server
6
6
  include Unchained::Client::Mixins::Resource
7
- resource({
8
- :access_level => 'accessLevel',
9
- :channel_id => 'channelID',
10
- :host => 'host',
11
- :name => 'name',
12
- :player_maximum => 'playerMaximum',
13
- :shard_id => 'shardID',
14
- })
7
+
8
+ attribute :access_level, Integer, json: 'accessLevel'
9
+ attribute :channel_id, Integer, json: 'channelID'
10
+ attribute :host, String
11
+ attribute :name, String
12
+ attribute :player_maximum, Integer, json: 'playerMaximum'
13
+ attribute :shard_id, Integer, json: 'shardID'
15
14
  end
16
15
 
17
- def servers(opts={})
18
- get_resources("#{base_url}/servers", Server, opts)
16
+ def servers(opts={}, channel: nil)
17
+ url = "#{base_url}/servers"
18
+ url += "/#{channel}" unless channel.nil?
19
+ get_resources(url, Server, opts)
19
20
  end
20
21
 
21
22
  end
@@ -3,5 +3,7 @@ module Unchained
3
3
  # TODO: Support more errors.
4
4
  class Error < StandardError; end
5
5
  class NotFound < Error; end
6
+ class InvalidValue < Error; end
7
+ class InvalidAttribute < Error; end
6
8
 
7
9
  end
@@ -16,9 +16,13 @@ module Unchained
16
16
  end
17
17
  end
18
18
 
19
+ def get_resource(url, resource_class, params={})
20
+ resource_class.from_json(get(url, params))
21
+ end
22
+
19
23
  def get_resources(url, resource_class, params={})
20
24
  get(url, params).map do |result|
21
- resource_class.decode_result(result)
25
+ resource_class.from_json(result)
22
26
  end
23
27
  end
24
28