clash_of_clans_api 0.1.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/README.adoc +39 -7
  3. data/lib/clash_of_clans_api/api.rb +41 -33
  4. data/lib/clash_of_clans_api/client.rb +41 -15
  5. data/lib/clash_of_clans_api/models/achievement.rb +15 -0
  6. data/lib/clash_of_clans_api/models/base.rb +56 -29
  7. data/lib/clash_of_clans_api/models/builder_base_league.rb +10 -0
  8. data/lib/clash_of_clans_api/models/capital_league.rb +10 -0
  9. data/lib/clash_of_clans_api/models/chat_language.rb +11 -0
  10. data/lib/clash_of_clans_api/models/clan.rb +44 -0
  11. data/lib/clash_of_clans_api/models/clan_capital.rb +11 -0
  12. data/lib/clash_of_clans_api/models/clan_capital_district.rb +11 -0
  13. data/lib/clash_of_clans_api/models/clan_location.rb +11 -0
  14. data/lib/clash_of_clans_api/models/hero.rb +12 -0
  15. data/lib/clash_of_clans_api/models/label.rb +12 -0
  16. data/lib/clash_of_clans_api/models/league.rb +1 -1
  17. data/lib/clash_of_clans_api/models/legend_season.rb +11 -0
  18. data/lib/clash_of_clans_api/models/legend_statistics.rb +13 -0
  19. data/lib/clash_of_clans_api/models/paginated_response.rb +19 -0
  20. data/lib/clash_of_clans_api/models/pagination_cursors.rb +10 -0
  21. data/lib/clash_of_clans_api/models/pagination_paging.rb +10 -0
  22. data/lib/clash_of_clans_api/models/player.rb +51 -0
  23. data/lib/clash_of_clans_api/models/player_house.rb +10 -0
  24. data/lib/clash_of_clans_api/models/player_house_element.rb +10 -0
  25. data/lib/clash_of_clans_api/models/spell.rb +12 -0
  26. data/lib/clash_of_clans_api/models/token.rb +1 -7
  27. data/lib/clash_of_clans_api/models/troop.rb +13 -0
  28. data/lib/clash_of_clans_api/models/war.rb +18 -0
  29. data/lib/clash_of_clans_api/models/war_attack.rb +14 -0
  30. data/lib/clash_of_clans_api/models/war_clan.rb +19 -0
  31. data/lib/clash_of_clans_api/models/war_clan_member.rb +16 -0
  32. data/lib/clash_of_clans_api/models/war_league.rb +10 -0
  33. data/lib/clash_of_clans_api/token_api.rb +2 -2
  34. data/lib/clash_of_clans_api/token_client.rb +16 -2
  35. data/lib/clash_of_clans_api/utils.rb +1 -26
  36. data/lib/clash_of_clans_api/version.rb +1 -1
  37. metadata +45 -7
  38. data/lib/clash_of_clans_api/endpoint_methods.rb +0 -68
  39. data/lib/clash_of_clans_api/no_success_error.rb +0 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a2b63aa46b4c6536b5c3c86729addc9e5dfa9c8071fdc890d24eed29d8768010
4
- data.tar.gz: 4c2a7bf252282acd7f5254b22eab7fe5f273dd740c0179fb04926af0d8295fef
3
+ metadata.gz: c028d861e525d6323453207f3f14885ed9df98346013bd5f586b34e79f95bd41
4
+ data.tar.gz: b39deae44556a97575faa02e5902a945bff658ad77367fb8f616045e2b705da7
5
5
  SHA512:
6
- metadata.gz: b9735602b7013aa396f555b1aca1d7dfc560cd6a46b27fd290275195f1a759c3789d116076ff10fe5ef5c8762371dfa2fdbebebc8f60930adf686c80b460aafe
7
- data.tar.gz: ccdb84b96e9c4db19c6e1bb89cd142fdd200c22b953d3f4ed6e45051bc13b137d7e23d247487842dcc915fe7c97f07550813fcbb834657add06799e967a7563f
6
+ metadata.gz: fffdf976c06723cc81d1134c58f832e24804729420d33fb3bc7645595ef6c0a54b45bcdfcbc68264ca6dfdaf58b525adde6cf7ac15802cdc30dae67e2ce08f16
7
+ data.tar.gz: 37644654dd7fdaa88b98d93648cd738a0aec546bf59be37e1443a69cd847b7219bf7426d56226aa1b43f19a59689f007b2be9bce3033ccee6b1d845851e0ea21
data/README.adoc CHANGED
@@ -28,12 +28,12 @@ $ gem install clash_of_clans_api
28
28
 
29
29
  ==== API Communication
30
30
 
31
- To communicate with the Clash of Clans API, an API access token is required.
32
- Currently, the gem is not able to create tokens itself.
31
+ To communicate with the Clash of Clans API, an API key is required.
32
+ If you like to use the library to create and manage API keys, see <<Token API>>.
33
33
 
34
34
  The gem provides two classes for communication.
35
35
  `ClashOfClansApi::Api` is a low-level interface that implements methods for all API endpoints.
36
- If the request is successful, the API’s JSON response is parsed and returned, otherwise a `ClashOfClans::NoSucessError` is raised.
36
+ If the request is successful, the API’s JSON response is parsed and returned, otherwise an `ApiFrame::NoSuccessError` is raised.
37
37
  `ClashOfClansApi::Client` is a higher-level interface that exposes its `ClashOfClansApi::Api` instance through `ClashOfClansApi::Client#api`.
38
38
  Both classes’ initializers take a single argument, the API token.
39
39
 
@@ -44,20 +44,52 @@ They are derived from the https://developer.clashofclans.com/#/documentation[API
44
44
  . Replace slashes (`/`) with underscores (`\_`) and keep only inner ones (`clans_{clanTag}_currentwar_leaguegroup`).
45
45
  . In case of path arguments, singularize the path segment referenced by the argument (`clan_{clanTag}_currentwar_leaguegroup`).
46
46
  . Remove path argument segments (`clan_currentwar_leaguegroup`).
47
+ . Remove any hyphens.
47
48
 
48
49
  Path arguments are converted to positional arguments in the order of definition in the original path name.
49
50
  Path arguments will automatically be URL-escaped.
50
51
  A URL query in the form of a `Hash` can be passed as the named parameter `query:`.
51
52
 
53
+ ==== Token API
54
+
55
+ Creating, listing and deleting API keys (tokens) is supported in `ClashOfClansApi::TokenClient` using the email address and password from the Clash of Clans Developer website.
56
+
57
+ [source,ruby]
58
+ ----
59
+ token_client = ClashOfClansApi::TokenClient.new(email, password)
60
+ token_client.login!
61
+
62
+ # Return a list of the currently registered API keys.
63
+ token_client.list_api_keys
64
+
65
+ # Create a new API key for the IP address 127.0.0.1 and create a ClashOfClansApi::Client from it.
66
+ token = token_client.create_api_key('my_key_name', 'This is a description for my API key.', ['127.0.0.1'])
67
+ client = token.client_from_token
68
+
69
+ # Create or get an API key with the given name for the current IPv4 address.
70
+ other_token = token_client.create_or_get_api_key_for_current_ipv4_address('test_key_name', overwrite: true)
71
+
72
+ # Revoke the previously generated tokens.
73
+ token_client.revoke_api_key(token.id)
74
+ other_token.revoke
75
+
76
+ # Logging out is not required, but possible.
77
+ token_client.logout
78
+ ----
79
+
80
+ This feature can be useful for applications whose host changes their IP address without human interaction as well as for large (federated) applications with too many requests for a single or a few manually created tokens.
81
+
82
+ Similar to `ClashOfClansApi::Api` and `ClashOfClansApi::Client`, there is also a lower-level implementation of the token API in `ClashOfClansApi::TokenApi`.
83
+ However, its usage is not recommended.
84
+
52
85
  ==== Clan and player tags
53
86
 
54
87
  Tags in Clash of Clans are subject to format restrictions.
55
88
  Since those restrictions are well known, `ClashOfClansApi::Tags` provides class methods for checking the format (`.sanitizable?`) and sanitizing ill-formatted tags up to a certain degree (`.sanitize`).
56
89
 
57
- Even though the API seems to ignore some mistakes, e.g. using `O` (upper case letter o) instead of `0` (number zero), it also does not seem to correct them.
58
- If a player with tag `#PY0` existed, the API would return the same information for both `#PY0` and `#PYO`, except using the tag that was requested.
59
- This could lead to unforeseen errors like multiple database entries for the same player or clan.
60
- Therefore, those mistakes should be catched before sending a request.
90
+ Since the beginning of 2022, the API consistently corrects the letter `O` in requests to the number `0`, which was not the case before.
91
+ Previously, this could lead to multiple database entries for the same player, which the `.sanitize` method could prevent.
92
+ While this isn’t a problem anymore in this specific use case, it might come in handy for querying user input in ones own database.
61
93
 
62
94
 
63
95
  === Development
@@ -1,10 +1,10 @@
1
- require_relative 'endpoint_methods'
2
- require_relative 'no_success_error'
1
+ require 'api_frame'
2
+
3
3
  require_relative 'utils'
4
4
 
5
5
  module ClashOfClansApi
6
6
  class Api
7
- include EndpointMethods
7
+ include ApiFrame::EndpointMethods
8
8
 
9
9
  BASE_URI = URI('https://api.clashofclans.com/v1/')
10
10
 
@@ -18,40 +18,48 @@ module ClashOfClansApi
18
18
  @api_token = api_token
19
19
  end
20
20
 
21
- def endpoint_headers
21
+ def default_headers
22
22
  {
23
23
  'Authorization' => "Bearer #{api_token}",
24
24
  }
25
25
  end
26
26
 
27
- define_endpoint :clan_currentwar_leaguegroup, method: :get, endpoint: proc { |clan_tag | "clans/#{Utils.url_escape(clan_tag)}/currentwar/leaguegroup" }
28
- define_endpoint :clanwarleagues_war, method: :get, endpoint: proc { | war_tag | "clanwarleagues/wars/#{Utils.url_escape(war_tag)}" }
29
- define_endpoint :clan_warlog, method: :get, endpoint: proc { |clan_tag | "clans/#{Utils.url_escape(clan_tag)}/warlog" }
30
- define_endpoint :clans, method: :get, endpoint: 'clans'
31
- define_endpoint :clan_currentwar, method: :get, endpoint: proc { |clan_tag | "clans/#{Utils.url_escape(clan_tag)}/currentwar" }
32
- define_endpoint :clan, method: :get, endpoint: proc { |clan_tag | "clans/#{Utils.url_escape(clan_tag)}" }
33
- define_endpoint :clan_members, method: :get, endpoint: proc { |clan_tag | "clans/#{Utils.url_escape(clan_tag)}/members" }
34
-
35
- define_endpoint :player, method: :get, endpoint: proc { |player_tag | "players/#{Utils.url_escape(player_tag)}" }
36
- define_endpoint :player_verifytoken, method: :post, endpoint: proc { |player_tag | "players/#{Utils.url_escape(player_tag)}/verifytoken" }, body: proc { |token:| %Q[{"token":"#{token.to_s}"}] }
37
-
38
- define_endpoint :leagues, method: :get, endpoint: 'leagues'
39
- define_endpoint :league_season, method: :get, endpoint: proc { | league_id, season_id| "leagues/#{Utils.url_escape( league_id)}/seasons/#{Utils.url_escape(season_id)}" }
40
- define_endpoint :league, method: :get, endpoint: proc { | league_id | "leagues/#{Utils.url_escape( league_id)}" }
41
- define_endpoint :league_seasons, method: :get, endpoint: proc { | league_id | "leagues/#{Utils.url_escape( league_id)}/seasons" }
42
- define_endpoint :warleague, method: :get, endpoint: proc { |warleague_id | "warleagues/#{Utils.url_escape(warleague_id)}" }
43
- define_endpoint :warleagues, method: :get, endpoint: 'warleagues'
44
-
45
- define_endpoint :location_rankings_clans, method: :get, endpoint: proc { |location_id | "locations/#{Utils.url_escape(location_id)}/rankings/clans" }
46
- define_endpoint :location_rankings_players, method: :get, endpoint: proc { |location_id | "locations/#{Utils.url_escape(location_id)}/rankings/players" }
47
- define_endpoint :location_rankings_clansversus, method: :get, endpoint: proc { |location_id | "locations/#{Utils.url_escape(location_id)}/rankings/clans-versus" }
48
- define_endpoint :location_rankings_playersversus, method: :get, endpoint: proc { |location_id | "locations/#{Utils.url_escape(location_id)}/rankings/players-versus" }
49
- define_endpoint :locations, method: :get, endpoint: 'locations'
50
- define_endpoint :location, method: :get, endpoint: proc { |location_id | "locations/#{Utils.url_escape(location_id)}" }
51
-
52
- define_endpoint :goldpass_seasons_current, method: :get, endpoint: 'goldpass/seasons/current'
53
-
54
- define_endpoint :labels_players, method: :get, endpoint: 'labels/players'
55
- define_endpoint :labels_clans, method: :get, endpoint: 'labels/clans'
27
+ define_endpoint :clan_currentwar_leaguegroup, method: :get, endpoint: proc { |clan_tag| "clans/#{ApiFrame::Utils.url_escape(clan_tag)}/currentwar/leaguegroup" }
28
+ define_endpoint :clanwarleagues_war, method: :get, endpoint: proc { | war_tag| "clanwarleagues/wars/#{ApiFrame::Utils.url_escape(war_tag)}" }
29
+ define_endpoint :clan_warlog, method: :get, endpoint: proc { |clan_tag| "clans/#{ApiFrame::Utils.url_escape(clan_tag)}/warlog" }
30
+ define_endpoint :clans, method: :get, endpoint: 'clans'
31
+ define_endpoint :clan_currentwar, method: :get, endpoint: proc { |clan_tag| "clans/#{ApiFrame::Utils.url_escape(clan_tag)}/currentwar" }
32
+ define_endpoint :clan, method: :get, endpoint: proc { |clan_tag| "clans/#{ApiFrame::Utils.url_escape(clan_tag)}" }
33
+ define_endpoint :clan_members, method: :get, endpoint: proc { |clan_tag| "clans/#{ApiFrame::Utils.url_escape(clan_tag)}/members" }
34
+ define_endpoint :clan_capitalraidseasons, method: :get, endpoint: proc { |clan_tag| "clans/#{ApiFrame::Utils.url_escape(clan_tag)}/capitalraidseasons" }
35
+
36
+ define_endpoint :player, method: :get, endpoint: proc { |player_tag| "players/#{ApiFrame::Utils.url_escape(player_tag)}" }
37
+ define_endpoint :player_verifytoken, method: :post, endpoint: proc { |player_tag| "players/#{ApiFrame::Utils.url_escape(player_tag)}/verifytoken" }, body: proc { |token:| %Q({"token":"#{token}"}) }
38
+
39
+ define_endpoint :capitalleagues, method: :get, endpoint: 'capitalleagues'
40
+ define_endpoint :leagues, method: :get, endpoint: 'leagues'
41
+ define_endpoint :league_season, method: :get, endpoint: proc { | league_id, season_id | "leagues/#{ApiFrame::Utils.url_escape( league_id)}/seasons/#{ApiFrame::Utils.url_escape(season_id)}" }
42
+ define_endpoint :capitalleague, method: :get, endpoint: proc { | capitalleague_id | "capitalleagues/#{ApiFrame::Utils.url_escape( capitalleague_id)}" }
43
+ define_endpoint :builderbaseleague, method: :get, endpoint: proc { |builderbaseleague_id | "builderbaseleagues/#{ApiFrame::Utils.url_escape(builderbaseleague_id)}" }
44
+ define_endpoint :builderbaseleagues, method: :get, endpoint: 'builderbaseleagues'
45
+ define_endpoint :league, method: :get, endpoint: proc { | league_id | "leagues/#{ApiFrame::Utils.url_escape( league_id)}" }
46
+ define_endpoint :league_seasons, method: :get, endpoint: proc { | league_id | "leagues/#{ApiFrame::Utils.url_escape( league_id)}/seasons" }
47
+ define_endpoint :warleague, method: :get, endpoint: proc { | warleague_id | "warleagues/#{ApiFrame::Utils.url_escape( warleague_id)}" }
48
+ define_endpoint :warleagues, method: :get, endpoint: 'warleagues'
49
+
50
+ define_endpoint :location_rankings_clans, method: :get, endpoint: proc { |location_id| "locations/#{ApiFrame::Utils.url_escape(location_id)}/rankings/clans" }
51
+ define_endpoint :location_rankings_players, method: :get, endpoint: proc { |location_id| "locations/#{ApiFrame::Utils.url_escape(location_id)}/rankings/players" }
52
+ define_endpoint :location_rankings_clansversus, method: :get, endpoint: proc { |location_id| "locations/#{ApiFrame::Utils.url_escape(location_id)}/rankings/clans-versus" }
53
+ define_endpoint :location_rankings_playersbuilderbase, method: :get, endpoint: proc { |location_id| "locations/#{ApiFrame::Utils.url_escape(location_id)}/rankings/players-builder-base" }
54
+ define_endpoint :location_rankings_clansbuilderbase, method: :get, endpoint: proc { |location_id| "locations/#{ApiFrame::Utils.url_escape(location_id)}/rankings/clans-builder-base" }
55
+ define_endpoint :location_rankings_playersversus, method: :get, endpoint: proc { |location_id| "locations/#{ApiFrame::Utils.url_escape(location_id)}/rankings/players-versus" }
56
+ define_endpoint :locations, method: :get, endpoint: 'locations'
57
+ define_endpoint :location_rankings_capitals, method: :get, endpoint: proc { |location_id| "locations/#{ApiFrame::Utils.url_escape(location_id)}/rankings/capitals" }
58
+ define_endpoint :location, method: :get, endpoint: proc { |location_id| "locations/#{ApiFrame::Utils.url_escape(location_id)}" }
59
+
60
+ define_endpoint :goldpass_seasons_current, method: :get, endpoint: 'goldpass/seasons/current'
61
+
62
+ define_endpoint :labels_players, method: :get, endpoint: 'labels/players'
63
+ define_endpoint :labels_clans, method: :get, endpoint: 'labels/clans'
56
64
  end
57
65
  end
@@ -1,5 +1,9 @@
1
1
  require_relative 'api'
2
+ require_relative 'models/paginated_response'
3
+ require_relative 'models/clan'
4
+ require_relative 'models/player'
2
5
  require_relative 'models/league'
6
+ require_relative 'models/war'
3
7
 
4
8
  module ClashOfClansApi
5
9
  class Client
@@ -10,7 +14,27 @@ module ClashOfClansApi
10
14
  end
11
15
 
12
16
  def authorized?
13
- api.perform_get('test').code == '404'
17
+ api.perform_request(:get, 'test').code == '404'
18
+ end
19
+
20
+ def clan_currentwar(clan_tag)
21
+ Models::War.new(api.clan_currentwar(clan_tag), self)
22
+ end
23
+
24
+ def clan_warlog(clan_tag)
25
+ Models::PaginatedResponse.new(Models::War, api.clan_warlog(clan_tag), self)
26
+ end
27
+
28
+ def clan(tag)
29
+ Models::Clan.new(api.clan(tag), self)
30
+ end
31
+
32
+ def clan_members(tag)
33
+ Models::PaginatedResponse.new(Models::Player, api.clan_members(tag), self)
34
+ end
35
+
36
+ def player(tag)
37
+ Models::Player.new(api.player(tag), self)
14
38
  end
15
39
 
16
40
  def player_verifytoken(player_tag, token)
@@ -20,27 +44,29 @@ module ClashOfClansApi
20
44
  raise "Sent token #{ token .inspect} but received #{response['token'].inspect}." unless token == response['token']
21
45
 
22
46
  case response['status']
23
- when 'ok'
24
- true
25
- when 'invalid'
26
- false
27
- else
28
- raise "Unknown status #{response['status'].inspect}."
47
+ when 'ok'
48
+ true
49
+ when 'invalid'
50
+ false
51
+ else
52
+ raise "Unknown status #{response['status'].inspect}."
29
53
  end
30
54
  end
31
55
 
56
+ def capitalleagues
57
+ Models::PaginatedResponse.new(Models::CapitalLeague, api.capitalleagues, self)
58
+ end
59
+
32
60
  def leagues
33
- response = api.leagues
34
-
35
- raise NotImplementedError, "Found a paging cursor but handling it is not implemented yet." if response['paging']['cursors'].any?
36
-
37
- response['items'].map do |league|
38
- Models::League.new(league)
39
- end
61
+ Models::PaginatedResponse.new(Models::League, api.leagues, self)
62
+ end
63
+
64
+ def league_season(league_id=29000022, season_id, limit: 10, before: nil, after: nil) # rubocop:disable Style/OptionalArguments
65
+ Models::PaginatedResponse.new(Models::Player, api.league_season(league_id, season_id, query: {limit: limit, before: before, after: after}.compact), self)
40
66
  end
41
67
 
42
68
  def league(id)
43
- Models::League.new(api.league(id))
69
+ Models::League.new(api.league(id), self)
44
70
  end
45
71
  end
46
72
  end
@@ -0,0 +1,15 @@
1
+ require_relative 'base'
2
+
3
+ module ClashOfClansApi
4
+ module Models
5
+ class Achievement < Base
6
+ property :name, 'name', required: true
7
+ property :stars, 'stars', required: true
8
+ property :value, 'value', required: true
9
+ property :target, 'target', required: true
10
+ property :info, 'info', required: true
11
+ property :completion_info, 'completionInfo', required: true
12
+ property :village, 'village', required: true
13
+ end
14
+ end
15
+ end
@@ -1,10 +1,14 @@
1
1
  require_relative 'invalid_data_error'
2
+ require 'date'
2
3
 
3
4
  module ClashOfClansApi
4
5
  module Models
5
6
  class Base
6
- def initialize(hash)
7
- @hash = hash
7
+ attr_reader :client
8
+
9
+ def initialize(hash, client)
10
+ @hash = hash
11
+ @client = client
8
12
 
9
13
  validate!
10
14
  end
@@ -18,52 +22,75 @@ module ClashOfClansApi
18
22
  end
19
23
 
20
24
  class << self
21
- attr_reader :required_fields
25
+ def registered_properties
26
+ @registered_properties ||= {}
27
+ end
22
28
 
23
- def property(name, key, type: nil, required: false)
24
- define_method(name) do
25
- if type.nil?
29
+ def property(method_name, key, type: nil, required: false, default: nil)
30
+ define_method(method_name) do
31
+ deduced_type =
32
+ case type
33
+ when Symbol
34
+ send(type)
35
+ when String
36
+ self.class.const_get(type)
37
+ else
38
+ type
39
+ end
40
+
41
+ if !@hash.key?(key)
42
+ default
43
+ elsif deduced_type.nil?
26
44
  self[key]
45
+ elsif property_cached?(method_name)
46
+ property_from_cache(method_name)
27
47
  else
28
- if property_cached?(name)
29
- property_from_cache(name)
30
- else
31
- cache_property(name, self[key].then do |prop|
32
- prop.is_a?(Array) ? prop.map {|item| type.new(item) } : type.new(prop)
33
- end)
48
+ initializer_proc = proc do |item|
49
+ if deduced_type.ancestors.include?(ClashOfClansApi::Models::Base)
50
+ deduced_type.new(item, self.client)
51
+ elsif deduced_type == DateTime
52
+ DateTime.parse(item)
53
+ else
54
+ deduced_type.new(item)
55
+ end
34
56
  end
57
+
58
+ cache_property(method_name, self[key].then do |prop|
59
+ prop.is_a?(Array) ? prop.map(&initializer_proc) : initializer_proc.call(prop)
60
+ end)
35
61
  end
36
62
  end
37
63
 
38
- if required
39
- @required_fields = (@required_fields || [])+[key]
40
- end
64
+ registered_properties[key] = {
65
+ method_name: method_name,
66
+ required: required,
67
+ default: default,
68
+ type: type,
69
+ }
41
70
  end
42
71
  end
43
72
 
44
- def property_cached?(name)
45
- @property_cache && @property_cache.key?(name)
73
+ def property_cached?(method_name)
74
+ @property_cache && @property_cache.key?(method_name)
46
75
  end
47
76
 
48
- def cache_property(name, obj)
77
+ def cache_property(method_name, obj)
49
78
  @property_cache ||= {}
50
79
 
51
- @property_cache[name] = obj
80
+ @property_cache[method_name] = obj
52
81
  end
53
82
 
54
- def property_from_cache(name)
55
- @property_cache[name]
83
+ def property_from_cache(method_name)
84
+ @property_cache[method_name]
56
85
  end
57
86
 
58
87
  def validate!
59
- if self.class.required_fields
60
- missing = self.class.required_fields.reject do |required_field|
61
- @hash.key?(required_field)
62
- end
63
-
64
- if missing.any?
65
- raise InvalidDataError, "The following keys are required, but missing from the model data: #{missing.map(&:inspect).join(', ')}"
66
- end
88
+ missing = self.class.registered_properties.reject do |field_name, properties|
89
+ !properties[:required] || @hash.key?(field_name)
90
+ end
91
+
92
+ if missing.any?
93
+ raise InvalidDataError, "The following keys are required, but missing from the model data: #{missing.keys.map(&:inspect).join(', ')}"
67
94
  end
68
95
  end
69
96
  end
@@ -0,0 +1,10 @@
1
+ require_relative 'base'
2
+
3
+ module ClashOfClansApi
4
+ module Models
5
+ class BuilderBaseLeague < Base
6
+ property :id, 'id', required: true
7
+ property :name, 'name', required: true
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ require_relative 'base'
2
+
3
+ module ClashOfClansApi
4
+ module Models
5
+ class CapitalLeague < Base
6
+ property :id, 'id', required: true
7
+ property :name, 'name', required: true
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ require_relative 'base'
2
+
3
+ module ClashOfClansApi
4
+ module Models
5
+ class ChatLanguage < Base
6
+ property :id, 'id', required: true
7
+ property :name, 'name', required: true
8
+ property :language_code, 'languageCode', required: true
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,44 @@
1
+ require_relative 'base'
2
+ require_relative 'capital_league'
3
+ require_relative 'chat_language'
4
+ require_relative 'clan_capital'
5
+ require_relative 'clan_location'
6
+ require_relative 'icon_set'
7
+ require_relative 'label'
8
+ require_relative 'war_league'
9
+
10
+ module ClashOfClansApi
11
+ module Models
12
+ class Clan < Base
13
+ property :tag, 'tag', required: true
14
+ property :name, 'name', required: true
15
+ property :type, 'type'
16
+ property :description, 'description'
17
+ property :location, 'location', type: ClanLocation
18
+ property :family_friendly?, 'isFamilyFriendly'
19
+ property :badge_urls, 'badgeUrls', type: IconSet
20
+ property :clan_level, 'clanLevel'
21
+ property :clan_points, 'clanPoints'
22
+ property :clan_builder_base_points, 'clanBuilderBasePoints'
23
+ property :clan_versus_points, 'clanVersusPoints'
24
+ property :clan_capital_points, 'clanCapitalPoints'
25
+ property :capital_league, 'capitalLeague', type: CapitalLeague
26
+ property :required_trophies, 'requiredTrophies'
27
+ property :war_frequency, 'warFrequency'
28
+ property :war_win_streak, 'warWinStreak'
29
+ property :war_wins, 'warWins'
30
+ property :war_ties, 'warTies'
31
+ property :war_losses, 'warLosses'
32
+ property :war_log_public?, 'isWarLogPublic'
33
+ property :war_league, 'warLeague', type: WarLeague
34
+ property :members, 'members'
35
+ property :member_list, 'memberList', type: 'ClashOfClansApi::Models::Player'
36
+ property :labels, 'labels', type: Label
37
+ property :required_builder_base_trophies, 'requiredBuilderBaseTrophies'
38
+ property :required_versus_trophies, 'requiredVersusTrophies'
39
+ property :required_townhall_level, 'requiredTownhallLevel'
40
+ property :clan_capital, 'clanCapital', type: ClanCapital
41
+ property :chat_language, 'chatLanguage', type: ChatLanguage
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,11 @@
1
+ require_relative 'base'
2
+ require_relative 'clan_capital_district'
3
+
4
+ module ClashOfClansApi
5
+ module Models
6
+ class ClanCapital < Base
7
+ property :capital_hall_level, 'capitalHallLevel', required: true
8
+ property :districts, 'districts', required: true, type: ClanCapitalDistrict
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require_relative 'base'
2
+
3
+ module ClashOfClansApi
4
+ module Models
5
+ class ClanCapitalDistrict < Base
6
+ property :id, 'id', required: true
7
+ property :name, 'name', required: true
8
+ property :district_hall_level, 'districtHallLevel', required: true
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require_relative 'base'
2
+
3
+ module ClashOfClansApi
4
+ module Models
5
+ class ClanLocation < Base
6
+ property :id, 'id', required: true
7
+ property :name, 'name', required: true
8
+ property :country?, 'isCountry', required: true
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ require_relative 'base'
2
+
3
+ module ClashOfClansApi
4
+ module Models
5
+ class Hero < Base
6
+ property :name, 'name', required: true
7
+ property :level, 'level', required: true
8
+ property :max_level, 'maxLevel', required: true
9
+ property :village, 'village', required: true
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ require_relative 'base'
2
+ require_relative 'icon_set'
3
+
4
+ module ClashOfClansApi
5
+ module Models
6
+ class Label < Base
7
+ property :id, 'id', required: true
8
+ property :name, 'name', required: true
9
+ property :icon_urls, 'iconUrls', required: true, type: IconSet
10
+ end
11
+ end
12
+ end
@@ -6,7 +6,7 @@ module ClashOfClansApi
6
6
  class League < Base
7
7
  property :id, 'id', required: true
8
8
  property :name, 'name', required: true
9
- property :icon_urls, 'iconUrls', type: IconSet
9
+ property :icon_urls, 'iconUrls', required: true, type: IconSet
10
10
  end
11
11
  end
12
12
  end
@@ -0,0 +1,11 @@
1
+ require_relative 'base'
2
+
3
+ module ClashOfClansApi
4
+ module Models
5
+ class LegendSeason < Base
6
+ property :id, 'id', required: false
7
+ property :rank, 'rank', required: true
8
+ property :trophies, 'trophies', required: true
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ require_relative 'base'
2
+ require_relative 'legend_season'
3
+
4
+ module ClashOfClansApi
5
+ module Models
6
+ class LegendStatistics < Base
7
+ property :legend_trophies, 'legendTrophies', required: true
8
+ property :previous_season, 'previousSeason', required: true, type: LegendSeason
9
+ property :best_season, 'bestSeason', required: true, type: LegendSeason
10
+ property :current_season, 'currentSeason', required: true, type: LegendSeason
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,19 @@
1
+ require_relative 'base'
2
+ require_relative 'pagination_paging'
3
+
4
+ module ClashOfClansApi
5
+ module Models
6
+ class PaginatedResponse < Base
7
+ attr_accessor :item_type
8
+
9
+ property :items, 'items', required: true, type: :item_type
10
+ property :paging, 'paging', required: true, type: PaginationPaging
11
+
12
+ def initialize(item_type, hash, client)
13
+ self.item_type = item_type
14
+
15
+ super(hash, client)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,10 @@
1
+ require_relative 'base'
2
+
3
+ module ClashOfClansApi
4
+ module Models
5
+ class PaginationCursors < Base
6
+ property :after, 'after'
7
+ property :before, 'before'
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ require_relative 'base'
2
+ require_relative 'pagination_cursors'
3
+
4
+ module ClashOfClansApi
5
+ module Models
6
+ class PaginationPaging < Base
7
+ property :cursors, 'cursors', required: true, type: PaginationCursors
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,51 @@
1
+ require_relative 'base'
2
+ require_relative 'achievement'
3
+ require_relative 'builder_base_league'
4
+ require_relative 'hero'
5
+ require_relative 'label'
6
+ require_relative 'league'
7
+ require_relative 'legend_statistics'
8
+ require_relative 'player_house'
9
+ require_relative 'spell'
10
+ require_relative 'troop'
11
+
12
+ module ClashOfClansApi
13
+ module Models
14
+ class Player < Base
15
+ property :tag, 'tag', required: true
16
+ property :name, 'name', required: true
17
+ property :town_hall_level, 'townHallLevel'
18
+ property :town_hall_weapon_level, 'townHallWeaponLevel'
19
+ property :exp_level, 'expLevel'
20
+ property :trophies, 'trophies'
21
+ property :best_trophies, 'bestTrophies'
22
+ property :war_stars, 'warStars'
23
+ property :attack_wins, 'attackWins'
24
+ property :defense_wins, 'defenseWins'
25
+ property :builder_hall_level, 'builderHallLevel'
26
+ property :builder_base_trophies, 'builderBaseTrophies'
27
+ property :versus_trophies, 'versusTrophies'
28
+ property :best_builder_base_trophies, 'bestBuilderBaseTrophies'
29
+ property :best_versus_trophies, 'bestVersusTrophies'
30
+ property :versus_battle_wins, 'versusBattleWins'
31
+ property :role, 'role'
32
+ property :war_preference, 'warPreference'
33
+ property :clan_rank, 'clanRank'
34
+ property :previous_clan_rank, 'previousClanRank'
35
+ property :donations, 'donations'
36
+ property :donations_received, 'donationsReceived'
37
+ property :rank, 'rank'
38
+ property :clan_capital_contributions, 'clanCapitalContributions'
39
+ property :clan, 'clan', type: 'ClashOfClansApi::Models::Clan'
40
+ property :league, 'league', type: League
41
+ property :builder_base_league, 'builderBaseLeague', type: BuilderBaseLeague
42
+ property :legend_statistics, 'legendStatistics', type: LegendStatistics
43
+ property :achievements, 'achievements', type: Achievement
44
+ property :player_house, 'playerHouse', type: PlayerHouse
45
+ property :labels, 'labels', type: Label
46
+ property :troops, 'troops', type: Troop
47
+ property :heroes, 'heroes', type: Hero
48
+ property :spells, 'spells', type: Spell
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,10 @@
1
+ require_relative 'base'
2
+ require_relative 'player_house_element'
3
+
4
+ module ClashOfClansApi
5
+ module Models
6
+ class PlayerHouse < Base
7
+ property :elements, 'elements', type: PlayerHouseElement, required: true
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ require_relative 'base'
2
+
3
+ module ClashOfClansApi
4
+ module Models
5
+ class PlayerHouseElement < Base
6
+ property :type, 'type', required: true
7
+ property :id, 'id', required: true
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ require_relative 'base'
2
+
3
+ module ClashOfClansApi
4
+ module Models
5
+ class Spell < Base
6
+ property :name, 'name', required: true
7
+ property :level, 'level', required: true
8
+ property :max_level, 'maxLevel', required: true
9
+ property :village, 'village', required: true
10
+ end
11
+ end
12
+ end
@@ -14,14 +14,8 @@ module ClashOfClansApi
14
14
  property :valid_until, 'validUntil'
15
15
  property :key, 'key', required: true
16
16
 
17
- def initialize(hash, token_client:)
18
- super(hash)
19
-
20
- @token_client = token_client
21
- end
22
-
23
17
  def revoke
24
- @token_client.revoke_api_key(self.id)
18
+ self.client.revoke_api_key(self.id)
25
19
  end
26
20
 
27
21
  def client_from_token
@@ -0,0 +1,13 @@
1
+ require_relative 'base'
2
+
3
+ module ClashOfClansApi
4
+ module Models
5
+ class Troop < Base
6
+ property :name, 'name', required: true
7
+ property :level, 'level', required: true
8
+ property :max_level, 'maxLevel', required: true
9
+ property :village, 'village', required: true
10
+ property :super_troop_is_active, 'superTroopIsActive', required: false, default: false
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ require_relative 'base'
2
+ require_relative 'war_clan'
3
+
4
+ module ClashOfClansApi
5
+ module Models
6
+ class War < Base
7
+ property :state, 'state'
8
+ property :result, 'result'
9
+ property :start_time, 'startTime', type: DateTime
10
+ property :end_time, 'endTime', type: DateTime
11
+ property :preparation_start_time, 'preparationStartTime', type: DateTime
12
+ property :team_size, 'teamSize'
13
+ property :attacks_per_member, 'attacksPerMember'
14
+ property :clan, 'clan', required: true, type: WarClan
15
+ property :opponent, 'opponent', required: true, type: WarClan
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ require_relative 'base'
2
+
3
+ module ClashOfClansApi
4
+ module Models
5
+ class WarAttack < Base
6
+ property :attacker_tag, 'attackerTag', required: true
7
+ property :defender_tag, 'defenderTag', required: true
8
+ property :stars, 'stars', required: true
9
+ property :destruction_percentage, 'destructionPercentage', required: true
10
+ property :order, 'order', required: true
11
+ property :duration, 'duration', required: true
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,19 @@
1
+ require_relative 'base'
2
+ require_relative 'icon_set'
3
+ require_relative 'war_clan_member'
4
+
5
+ module ClashOfClansApi
6
+ module Models
7
+ class WarClan < Base
8
+ property :tag, 'tag'
9
+ property :name, 'name'
10
+ property :badge_urls, 'badgeUrls', type: IconSet
11
+ property :clan_level, 'clanLevel'
12
+ property :attacks, 'attacks'
13
+ property :stars, 'stars'
14
+ property :destruction_percentage, 'destructionPercentage'
15
+ property :exp_earned, 'expEarned'
16
+ property :members, 'members', type: WarClanMember
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,16 @@
1
+ require_relative 'base'
2
+ require_relative 'war_attack'
3
+
4
+ module ClashOfClansApi
5
+ module Models
6
+ class WarClanMember < Base
7
+ property :tag, 'tag', required: true
8
+ property :name, 'name', required: true
9
+ property :townhall_level, 'townhallLevel'
10
+ property :map_position, 'mapPosition'
11
+ property :attacks, 'attacks', type: WarAttack
12
+ property :opponent_attacks, 'opponentAttacks'
13
+ property :best_opponent_attack, 'bestOpponentAttack', type: WarAttack
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,10 @@
1
+ require_relative 'base'
2
+
3
+ module ClashOfClansApi
4
+ module Models
5
+ class WarLeague < Base
6
+ property :id, 'id', required: true
7
+ property :name, 'name', required: true
8
+ end
9
+ end
10
+ end
@@ -1,11 +1,11 @@
1
- require_relative 'endpoint_methods'
1
+ require 'api_frame'
2
2
 
3
3
  module ClashOfClansApi
4
4
  module TokenApi
5
5
  BASE_URI = URI('https://developer.clashofclans.com/api/')
6
6
 
7
7
  class << self
8
- include EndpointMethods
8
+ include ApiFrame::EndpointMethods
9
9
 
10
10
  def base_uri
11
11
  BASE_URI
@@ -36,14 +36,14 @@ module ClashOfClansApi
36
36
  response = TokenApi.apikey_list(headers: @session_headers)
37
37
 
38
38
  response['keys'].map do |key|
39
- Models::Token.new(key, token_client: self)
39
+ Models::Token.new(key, self)
40
40
  end
41
41
  end
42
42
 
43
43
  def create_api_key(name, description, ip_addresses)
44
44
  response = TokenApi.apikey_create(name: name, description: description, ip_addresses: (ip_addresses.is_a?(Array) ? ip_addresses : [ip_addresses]), headers: @session_headers)
45
45
 
46
- Models::Token.new(response['key'], token_client: self)
46
+ Models::Token.new(response['key'], self)
47
47
  end
48
48
 
49
49
  def revoke_api_key(id)
@@ -52,6 +52,20 @@ module ClashOfClansApi
52
52
  true
53
53
  end
54
54
 
55
+ def create_or_get_api_key_for_current_ipv4_address(name, description=name, overwrite: false)
56
+ current_ipv4 = ClashOfClansApi::Utils.current_ipv4_address
57
+ token = list_api_keys.select{ |i| i.name == name }.first
58
+
59
+ if token && token.cidr_ranges.include?(current_ipv4)
60
+ token
61
+ elsif (token && overwrite) || !token
62
+ token&.revoke
63
+ create_api_key(name, description, current_ipv4)
64
+ else
65
+ false
66
+ end
67
+ end
68
+
55
69
  class << self
56
70
  def create!(email, password)
57
71
  new(email, password).login!
@@ -2,32 +2,7 @@ require 'open-uri'
2
2
 
3
3
  module ClashOfClansApi
4
4
  module Utils
5
- def self.url_escape(string)
6
- if !string.nil?
7
- CGI.escape(string.to_s)
8
- else
9
- raise TypeError, 'cannot escape nil'
10
- end
11
- end
12
-
13
- def self.call_proc_without_unknown_keywords(proc, *args, **kwargs, &block)
14
- params = proc.parameters.group_by(&:first).transform_values! do |m|
15
- m.map do |s|
16
- s[1]
17
- end
18
- end
19
-
20
- proc_keys =
21
- if params.key?(:keyrest)
22
- kwargs
23
- else
24
- kwargs.slice(*(params.values_at(:key, :keyreq).compact.flatten))
25
- end
26
-
27
- proc.call(*args, **proc_keys, &block)
28
- end
29
-
30
- def self.get_current_ipv4_address
5
+ def self.current_ipv4_address
31
6
  IPAddr.new(URI('https://ipv4.icanhazip.com').open.read.strip).to_s
32
7
  end
33
8
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ClashOfClansApi
4
- VERSION = '0.1.1'
4
+ VERSION = '0.3.0'
5
5
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: clash_of_clans_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - expeehaa
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-26 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2023-10-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: api_frame
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  description:
14
28
  email:
15
29
  - expeehaa@outlook.com
@@ -21,13 +35,36 @@ files:
21
35
  - lib/clash_of_clans_api.rb
22
36
  - lib/clash_of_clans_api/api.rb
23
37
  - lib/clash_of_clans_api/client.rb
24
- - lib/clash_of_clans_api/endpoint_methods.rb
38
+ - lib/clash_of_clans_api/models/achievement.rb
25
39
  - lib/clash_of_clans_api/models/base.rb
40
+ - lib/clash_of_clans_api/models/builder_base_league.rb
41
+ - lib/clash_of_clans_api/models/capital_league.rb
42
+ - lib/clash_of_clans_api/models/chat_language.rb
43
+ - lib/clash_of_clans_api/models/clan.rb
44
+ - lib/clash_of_clans_api/models/clan_capital.rb
45
+ - lib/clash_of_clans_api/models/clan_capital_district.rb
46
+ - lib/clash_of_clans_api/models/clan_location.rb
47
+ - lib/clash_of_clans_api/models/hero.rb
26
48
  - lib/clash_of_clans_api/models/icon_set.rb
27
49
  - lib/clash_of_clans_api/models/invalid_data_error.rb
50
+ - lib/clash_of_clans_api/models/label.rb
28
51
  - lib/clash_of_clans_api/models/league.rb
52
+ - lib/clash_of_clans_api/models/legend_season.rb
53
+ - lib/clash_of_clans_api/models/legend_statistics.rb
54
+ - lib/clash_of_clans_api/models/paginated_response.rb
55
+ - lib/clash_of_clans_api/models/pagination_cursors.rb
56
+ - lib/clash_of_clans_api/models/pagination_paging.rb
57
+ - lib/clash_of_clans_api/models/player.rb
58
+ - lib/clash_of_clans_api/models/player_house.rb
59
+ - lib/clash_of_clans_api/models/player_house_element.rb
60
+ - lib/clash_of_clans_api/models/spell.rb
29
61
  - lib/clash_of_clans_api/models/token.rb
30
- - lib/clash_of_clans_api/no_success_error.rb
62
+ - lib/clash_of_clans_api/models/troop.rb
63
+ - lib/clash_of_clans_api/models/war.rb
64
+ - lib/clash_of_clans_api/models/war_attack.rb
65
+ - lib/clash_of_clans_api/models/war_clan.rb
66
+ - lib/clash_of_clans_api/models/war_clan_member.rb
67
+ - lib/clash_of_clans_api/models/war_league.rb
31
68
  - lib/clash_of_clans_api/tags.rb
32
69
  - lib/clash_of_clans_api/token_api.rb
33
70
  - lib/clash_of_clans_api/token_client.rb
@@ -37,6 +74,7 @@ homepage: https://github.com/expeehaa/clash_of_clans_api
37
74
  licenses: []
38
75
  metadata:
39
76
  allowed_push_host: https://rubygems.org
77
+ rubygems_mfa_required: 'true'
40
78
  post_install_message:
41
79
  rdoc_options: []
42
80
  require_paths:
@@ -45,14 +83,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
45
83
  requirements:
46
84
  - - ">="
47
85
  - !ruby/object:Gem::Version
48
- version: 2.6.0
86
+ version: 2.7.0
49
87
  required_rubygems_version: !ruby/object:Gem::Requirement
50
88
  requirements:
51
89
  - - ">="
52
90
  - !ruby/object:Gem::Version
53
91
  version: '0'
54
92
  requirements: []
55
- rubygems_version: 3.2.22
93
+ rubygems_version: 3.4.10
56
94
  signing_key:
57
95
  specification_version: 4
58
96
  summary: Client library for interacting with the ClashOfClans API.
@@ -1,68 +0,0 @@
1
- require 'cgi'
2
- require 'json'
3
- require 'net/https'
4
-
5
- module ClashOfClansApi
6
- module EndpointMethods
7
- def endpoint_headers
8
- {}
9
- end
10
-
11
- def perform_request(method, api_path, query: nil, body: nil, headers: nil)
12
- uri = self.base_uri+api_path
13
- uri.query = URI.encode_www_form(query) if query
14
-
15
- Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme=='https') do |http|
16
- case method
17
- when :get
18
- Net::HTTP::Get
19
- when :post
20
- Net::HTTP::Post
21
- else
22
- raise ArgumentError, "Invalid method #{method.inspect}."
23
- end.new(uri).tap do |request|
24
- endpoint_headers.merge(headers || {}).each do |name, value|
25
- request[name] = value
26
- end
27
-
28
- if body
29
- request['Content-Type'] = 'application/json'
30
- request.body = body
31
- end
32
- end.then do |request|
33
- http.request(request)
34
- end
35
- end
36
- end
37
-
38
- def transform_response(response)
39
- if response.is_a?(Net::HTTPSuccess)
40
- JSON.parse(response.body)
41
- else
42
- raise NoSuccessError.new(response)
43
- end
44
- end
45
-
46
-
47
- def self.included(klass)
48
- klass.extend(ClassMethods)
49
- end
50
-
51
- module ClassMethods
52
- def define_endpoint(name, method:, endpoint:, body: nil)
53
- define_method(name) do |*args, **kwargs|
54
- uri = endpoint.respond_to?(:call) ? ClashOfClansApi::Utils.call_proc_without_unknown_keywords(endpoint, *args, **kwargs) : endpoint
55
- request_body = body .respond_to?(:call) ? ClashOfClansApi::Utils.call_proc_without_unknown_keywords(body, *args, **kwargs) : body
56
-
57
- perform_request(method, uri, body: request_body, query: kwargs.dig(:query), headers: kwargs.dig(:headers)).then do |response|
58
- if !kwargs.key?(:plain_response) || !kwargs.fetch(:plain_response)
59
- transform_response(response)
60
- else
61
- response
62
- end
63
- end
64
- end
65
- end
66
- end
67
- end
68
- end
@@ -1,9 +0,0 @@
1
- module ClashOfClansApi
2
- class NoSuccessError < StandardError
3
- attr_reader :response
4
-
5
- def initialize(response)
6
- @response = response
7
- end
8
- end
9
- end