foot_stats 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/.gitignore +18 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +72 -0
  6. data/Rakefile +1 -0
  7. data/foot_stats.gemspec +26 -0
  8. data/lib/foot_stats/championship.rb +66 -0
  9. data/lib/foot_stats/championship_classification.rb +55 -0
  10. data/lib/foot_stats/error_response.rb +13 -0
  11. data/lib/foot_stats/match.rb +77 -0
  12. data/lib/foot_stats/narration.rb +69 -0
  13. data/lib/foot_stats/request.rb +58 -0
  14. data/lib/foot_stats/resource.rb +27 -0
  15. data/lib/foot_stats/response.rb +61 -0
  16. data/lib/foot_stats/setup.rb +27 -0
  17. data/lib/foot_stats/team.rb +37 -0
  18. data/lib/foot_stats/version.rb +3 -0
  19. data/lib/foot_stats.rb +14 -0
  20. data/spec/cassettes/championship.yml +62 -0
  21. data/spec/cassettes/championship_classification.yml +76 -0
  22. data/spec/cassettes/championship_classification_error_response.yml +63 -0
  23. data/spec/cassettes/championship_match.yml +82 -0
  24. data/spec/cassettes/championship_match_error_response.yml +63 -0
  25. data/spec/cassettes/championship_teams.yml +68 -0
  26. data/spec/cassettes/championship_teams_error_response.yml +63 -0
  27. data/spec/cassettes/error_response.yml +62 -0
  28. data/spec/cassettes/match_narration.yml +83 -0
  29. data/spec/cassettes/match_narration_error_response.yml +63 -0
  30. data/spec/cassettes/match_null_narration.yml +73 -0
  31. data/spec/foot_stats/championship_classification_spec.rb +53 -0
  32. data/spec/foot_stats/championship_spec.rb +77 -0
  33. data/spec/foot_stats/match_spec.rb +67 -0
  34. data/spec/foot_stats/narration_spec.rb +69 -0
  35. data/spec/foot_stats/request_spec.rb +43 -0
  36. data/spec/foot_stats/response_spec.rb +72 -0
  37. data/spec/foot_stats/setup_spec.rb +6 -0
  38. data/spec/foot_stats/team_spec.rb +38 -0
  39. data/spec/spec_helper.rb +15 -0
  40. metadata +184 -0
data/.gitignore ADDED
@@ -0,0 +1,18 @@
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
18
+ .rvmrc
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color -f d
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in foot_stats.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 TODO: Write your name
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,72 @@
1
+ # FootStats
2
+
3
+ FootStats API Client in Ruby.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'foot_stats'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install foot_stats
18
+
19
+ ## Setup
20
+
21
+ ```ruby
22
+ FootStats::Setup.setup do |config|
23
+ config.username = "username"
24
+ config.password = "password"
25
+ config.logger = Rails.logger
26
+ config.base_url = "http://footstats.com"
27
+ end
28
+ ```
29
+
30
+ ## Usage
31
+
32
+ ```ruby
33
+ # Championship
34
+ #
35
+ championships = FootStats::Championship.all
36
+
37
+ # Championship
38
+ #
39
+ championship = championships.first
40
+
41
+ # Championship Classification
42
+ #
43
+ championship.classification
44
+
45
+ # Championship Teams
46
+ #
47
+ championship.teams
48
+
49
+ # Matches
50
+ #
51
+ matches = championship.matches
52
+
53
+ # Match
54
+ match = matches.first
55
+
56
+ # Narrations
57
+ #
58
+ match.narrations
59
+ ```
60
+
61
+ ## Next
62
+
63
+ * LIVE 'feed'.
64
+ * Create a Fake App (Sandbox), that simulates FootStats API.
65
+
66
+ ## Contributing
67
+
68
+ 1. Fork it
69
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
70
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
71
+ 4. Push to the branch (`git push origin my-new-feature`)
72
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'foot_stats/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "foot_stats"
8
+ gem.version = FootStats::VERSION
9
+ gem.authors = ["Tomas D'Stefano"]
10
+ gem.email = ["tomas_stefano@successoft.com"]
11
+ gem.description = %q{FootStats API Client in Ruby.}
12
+ gem.summary = %q{FootStats API Client.}
13
+ gem.homepage = "https://github.com/tomas-stefano/foot_stats"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency 'activesupport'
21
+ gem.add_dependency 'rest-client'
22
+
23
+ gem.add_development_dependency 'rspec'
24
+ gem.add_development_dependency 'vcr'
25
+ gem.add_development_dependency 'fakeweb'
26
+ end
@@ -0,0 +1,66 @@
1
+ module FootStats
2
+ class Championship < Resource
3
+ attr_accessor :source_id, :name, :has_classification, :current_round, :total_rounds
4
+
5
+ # Retrieve all championships from FootStats
6
+ #
7
+ # @return [Array]
8
+ #
9
+ def self.all
10
+ request = Request.new(self)
11
+ response = request.parse
12
+
13
+ return response.error if response.error?
14
+
15
+ response.collect do |championship|
16
+ new(
17
+ :source_id => championship['@Id'].to_i,
18
+ :name => championship['@Nome'],
19
+ :has_classification => championship['@TemClassificacao'] == 'True',
20
+ :current_round => championship['@RodadaATual'].to_i,
21
+ :total_rounds => championship['@Rodadas'].to_i
22
+ )
23
+ end
24
+ end
25
+
26
+ # Return the resource name to request to FootStats.
27
+ #
28
+ # @return [String]
29
+ #
30
+ def self.resource_name
31
+ 'ListaCampeonatos'
32
+ end
33
+
34
+ # Return the resource key that is fetch from the API response.
35
+ #
36
+ # @return [String]
37
+ #
38
+ def self.resource_key
39
+ 'Campeonato'
40
+ end
41
+
42
+ # Return the Championship classification.
43
+ #
44
+ # @return [Array]
45
+ #
46
+ def classification
47
+ ChampionshipClassification.all(championship: source_id)
48
+ end
49
+
50
+ # Return the Championship teams.
51
+ #
52
+ # @return [Array]
53
+ #
54
+ def teams
55
+ Team.all(championship: source_id)
56
+ end
57
+
58
+ # Return all the Championship matches.
59
+ #
60
+ # @return [Array]
61
+ #
62
+ def matches
63
+ Match.all(championship: source_id)
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,55 @@
1
+ module FootStats
2
+ class ChampionshipClassification < Resource
3
+ attr_accessor :team_source_id, :group, :position, :points, :games, :victories, :draws, :loss
4
+ attr_accessor :goals_for, :goals_against, :goals_balance, :home_victories, :outside_victories
5
+ attr_accessor :home_draws, :outside_draws, :home_defeats, :outside_defeats, :max_point
6
+ attr_accessor :use
7
+
8
+ def self.all(options={})
9
+ request = Request.new(self, :Campeonato => options.fetch(:championship))
10
+ response = request.parse
11
+
12
+ return response.error if response.error?
13
+
14
+ response["Classificacoes"]['Classificacao']['Equipe'].collect do |classification|
15
+ ChampionshipClassification.new(
16
+ :team_source_id => classification['@Id'].to_i,
17
+ :group => classification['@Grupo'],
18
+ :position => classification['Posicao'],
19
+ :points => classification['Pontos_Ganhos'],
20
+ :games => classification['Jogos'],
21
+ :victories => classification['Vitorias'],
22
+ :draws => classification['Empates'],
23
+ :loss => classification['Derrotas'],
24
+ :goals_for => classification['Gols_Pro'],
25
+ :goals_against => classification['Gols_Contra'],
26
+ :goals_balance => classification['Saldo_Gols'],
27
+ :home_victories => classification['Vitorias_Casa'],
28
+ :outside_victories => classification['Vitorias_Fora'],
29
+ :home_draws => classification['Empates_Casa'],
30
+ :outside_draws => classification['Empate_Fora'],
31
+ :home_defeats => classification['Derrotas_Casa'],
32
+ :outside_defeats => classification['Derrotas_Fora'],
33
+ :max_point => classification['Ponto_Maximo'],
34
+ :use => classification['Aproveitamento']
35
+ )
36
+ end
37
+ end
38
+
39
+ # Return the resource name to request to FootStats.
40
+ #
41
+ # @return [String]
42
+ #
43
+ def self.resource_name
44
+ 'ListaClassificacao'
45
+ end
46
+
47
+ # Return the resource key that is fetch from the API response.
48
+ #
49
+ # @return [String]
50
+ #
51
+ def self.resource_key
52
+ 'Campeonato'
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,13 @@
1
+ module FootStats
2
+ class ErrorResponse
3
+ attr_reader :message
4
+
5
+ def initialize(message)
6
+ @message = message
7
+ end
8
+
9
+ def ==(other)
10
+ @message == other.message
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,77 @@
1
+ module FootStats
2
+ class Match < Resource
3
+ attr_accessor :source_id, :date, :status, :referee, :stadium, :city, :state
4
+ attr_accessor :country, :has_statistic, :has_narration, :round, :phase
5
+ attr_accessor :cup, :group, :game_number, :live
6
+ attr_accessor :home_team, :home_team_name, :home_score, :home_penalties_score
7
+ attr_accessor :visitor_team, :visitor_team_name, :visitor_score, :visitor_penalties_score
8
+
9
+ def self.all(options={})
10
+ request = Request.new(self, :Campeonato => options.fetch(:championship))
11
+ response = request.parse
12
+
13
+ return response.error if response.error?
14
+
15
+ response['Partida'].collect do |match|
16
+ match_object = Match.new(
17
+ :source_id => match['@Id'].to_i,
18
+ :date => match['Data'],
19
+ :status => match['Status'],
20
+ :referee => match['Arbitro'],
21
+ :stadium => match['Estadio'],
22
+ :city => match['Cidade'],
23
+ :state => match['Estado'],
24
+ :country => match['Pais'],
25
+ :has_statistic => match['TemEstatistica'], # TODO: Need to see boolean
26
+ :has_narration => match['TemNarracao'], # fields.
27
+ :round => match['Rodada'],
28
+ :phase => match['Fase'],
29
+ :cup => match['Taca'],
30
+ :group => match['Grupo'],
31
+ :game_number => match['NumeroJogo'],
32
+ :live => match['AoVivo']
33
+ )
34
+
35
+ match['Equipe'].each do |team|
36
+ if team['@Tipo'] == 'Mandante'
37
+ match_object.home_team = team['@Id'].to_i
38
+ match_object.home_team_name = team['@Nome']
39
+ match_object.home_score = team['@Placar']
40
+ match_object.home_penalties_score = team['@PlacarPenaltis']
41
+ else
42
+ match_object.visitor_team = team['@Id'].to_i
43
+ match_object.visitor_team_name = team['@Nome']
44
+ match_object.visitor_score = team['@Placar']
45
+ match_object.visitor_penalties_score = team['@PlacarPenaltis']
46
+ end
47
+ end
48
+
49
+ match_object
50
+ end
51
+ end
52
+
53
+ # Return the resource name to request to FootStats.
54
+ #
55
+ # @return [String]
56
+ #
57
+ def self.resource_name
58
+ 'ListaPartidas'
59
+ end
60
+
61
+ # Return the resource key that is fetch from the API response.
62
+ #
63
+ # @return [String]
64
+ #
65
+ def self.resource_key
66
+ 'Partidas'
67
+ end
68
+
69
+ # Return the narration from a match
70
+ #
71
+ # @return [Array]
72
+ #
73
+ def narrations
74
+ Narration.all(match: source_id)
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,69 @@
1
+ module FootStats
2
+ class Narration < Resource
3
+ attr_accessor :championship_id, :name, :season, :match_id, :score, :has_penalty, :details
4
+
5
+ def self.all(options={})
6
+ request = Request.new(self, :Partida => options.fetch(:match))
7
+ response = request.parse
8
+
9
+ return response.error if response.error?
10
+
11
+ response.resource.collect do |match, value|
12
+ match_hash = response['Partida']
13
+ narrations = response['Narracoes'] || []
14
+
15
+ narration = Narration.new(
16
+ :championship_id => response['@Id'].to_i,
17
+ :name => response['@Nome'],
18
+ :season => response['@Temporada'],
19
+ :match_id => match_hash['@Id'].to_i,
20
+ :score => match_hash['@Placar'],
21
+ :has_penalty => match_hash['@TemDisputaPenaltis']
22
+ )
23
+
24
+ if narrations.empty?
25
+ narration.details = narrations
26
+ else
27
+ narration.details = []
28
+
29
+ narrations.each do |foot_stats_narration|
30
+ narration.details.push(NarrationDetail.new(
31
+ :source_id => foot_stats_narration["@Id"].to_i,
32
+ :team_source_id => foot_stats_narration["IdEquipe"].to_i,
33
+ :team_name => foot_stats_narration["NomeEquipe"],
34
+ :player_source_id => foot_stats_narration["IdJogador"].to_i,
35
+ :player_name => foot_stats_narration["NomeJogador"],
36
+ :period => foot_stats_narration["Periodo"],
37
+ :moment => foot_stats_narration["Momento"],
38
+ :description => foot_stats_narration["Descricao"],
39
+ :action => foot_stats_narration["Acao"]
40
+ ))
41
+ end
42
+ end
43
+
44
+ narration
45
+ end
46
+ end
47
+
48
+ # Return the resource name to request to FootStats.
49
+ #
50
+ # @return [String]
51
+ #
52
+ def self.resource_name
53
+ 'Narracao'
54
+ end
55
+
56
+ # Return the resource key that is fetch from the API response.
57
+ #
58
+ # @return [String]
59
+ #
60
+ def self.resource_key
61
+ 'Campeonato'
62
+ end
63
+ end
64
+
65
+ class NarrationDetail < Resource
66
+ attr_accessor :source_id, :team_source_id, :team_name, :player_source_id
67
+ attr_accessor :player_name, :period, :moment, :description, :action
68
+ end
69
+ end
@@ -0,0 +1,58 @@
1
+ require 'rest-client'
2
+
3
+ module FootStats
4
+ # Class responsible to make the request to the FootStats API
5
+ #
6
+ # @example
7
+ #
8
+ # Request.new('ListaCampeonatos')
9
+ #
10
+ class Request
11
+ attr_reader :response_body, :resource_name, :resource_key, :logger
12
+
13
+ def initialize(resource, options={})
14
+ @resource_name = resource.resource_name
15
+ @resource_key = resource.resource_key
16
+ @response_body = post(options)
17
+ @logger = Setup.logger
18
+ end
19
+
20
+ # Return the request uri based on the resource.
21
+ #
22
+ # @return [String]
23
+ #
24
+ def request_url
25
+ "#{Setup.base_url}/#{resource_name}"
26
+ end
27
+
28
+ # Make the post request to the request url.
29
+ #
30
+ # @return [String]
31
+ #
32
+ def post(options)
33
+ logger.info("POST #{request_url}") if logger.present?
34
+ response = RestClient.post(request_url, setup_params.merge(options))
35
+ logger.info("RESPONSE BODY:\n#{response}\n") if logger.present?
36
+ response
37
+ end
38
+
39
+ # Parse the "XML"/ "JSON".
40
+ #
41
+ # @return [Response]
42
+ #
43
+ def parse
44
+ Response.new(resource_key: @resource_key, body: @response_body)
45
+ end
46
+
47
+ # Passing the setup params configured in your app.
48
+ #
49
+ # @return [Hash]
50
+ #
51
+ def setup_params
52
+ {
53
+ :Usuario => Setup.username,
54
+ :Senha => Setup.password
55
+ }
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,27 @@
1
+ module FootStats
2
+ class Resource
3
+ # Waiting for ActiveModel::Model. =p
4
+ #
5
+ def initialize(options={})
6
+ options.each do |key, value|
7
+ send("#{key}=", value) if respond_to?("#{key}=")
8
+ end
9
+ end
10
+
11
+ # Return the resource name to request to FootStats.
12
+ #
13
+ # @return [String]
14
+ #
15
+ def self.resource_name
16
+ raise NotImplementedError, "need to implement .resource_name in #{self}."
17
+ end
18
+
19
+ # Return the resource key that is fetch from the API response.
20
+ #
21
+ # @return [String]
22
+ #
23
+ def self.resource_key
24
+ raise NotImplementedError, "need to implement .resource_key in #{self}."
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,61 @@
1
+ require 'active_support/json'
2
+
3
+ module FootStats
4
+ class Response
5
+ attr_accessor :resource_key, :body, :parsed_response
6
+ REGEX_PARSER = /\{.*}/m
7
+
8
+ def initialize(options={})
9
+ @resource_key = options.fetch(:resource_key)
10
+ @body = options.fetch(:body)
11
+ @parsed_response = ActiveSupport::JSON.decode(json_response)
12
+ end
13
+
14
+ # Return the error response object with the message if had errors.
15
+ #
16
+ # @return [ErrorResponse]
17
+ #
18
+ def error
19
+ ErrorResponse.new(@parsed_response['Erro']['@Mensagem']) if error?
20
+ end
21
+
22
+ # Verifies if the response had errors.
23
+ #
24
+ # @return [True, False]
25
+ #
26
+ def error?
27
+ @parsed_response['Erro'].present?
28
+ end
29
+
30
+ # Return the resource match by the resource key.
31
+ #
32
+ # @return [Hash]
33
+ #
34
+ def resource
35
+ @parsed_response[@resource_key]
36
+ end
37
+
38
+ # Attempt to fetch a key from resource.
39
+ #
40
+ # @return [Object]
41
+ #
42
+ def [](value)
43
+ resource[value]
44
+ end
45
+
46
+ # Collect all the resources evaluate from FootStats
47
+ #
48
+ # @return [Array]
49
+ #
50
+ def collect
51
+ resource.collect { |resource_value| yield(resource_value) }
52
+ end
53
+ alias :map :collect
54
+
55
+ private
56
+
57
+ def json_response
58
+ @body.scan(REGEX_PARSER).first
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,27 @@
1
+ require 'active_support/core_ext/class'
2
+
3
+ module FootStats
4
+ # Class responsible to handle all the FootStats setup.
5
+ #
6
+ # @example
7
+ #
8
+ # FootStats::Setup.setup do |config|
9
+ # config.username = "foo"
10
+ # config.password = "bar"
11
+ # config.logger = Rails.logger
12
+ # config.base_url = "http://footstats.com.br/modyo.asmx/"
13
+ # end
14
+ #
15
+ class Setup
16
+ cattr_accessor :username
17
+ cattr_accessor :password
18
+ cattr_accessor :logger
19
+ cattr_accessor :base_url
20
+
21
+ # @param block [Proc]
22
+ #
23
+ def self.setup
24
+ yield(self)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,37 @@
1
+ module FootStats
2
+ class Team < Resource
3
+ attr_accessor :source_id, :full_name, :city, :country
4
+
5
+ def self.all(options={})
6
+ request = Request.new(self, :IdCampeonato => options.fetch(:championship))
7
+ response = request.parse
8
+
9
+ return response.error if response.error?
10
+
11
+ response.collect do |team|
12
+ Team.new(
13
+ :source_id => team['@Id'].to_i,
14
+ :full_name => team['@Nome'],
15
+ :city => team['@Cidade'],
16
+ :country => team['@Pais']
17
+ )
18
+ end
19
+ end
20
+
21
+ # Return the resource name to request to FootStats.
22
+ #
23
+ # @return [String]
24
+ #
25
+ def self.resource_name
26
+ 'ListaEquipesCampeonato'
27
+ end
28
+
29
+ # Return the resource key that is fetch from the API response.
30
+ #
31
+ # @return [String]
32
+ #
33
+ def self.resource_key
34
+ 'Equipe'
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,3 @@
1
+ module FootStats
2
+ VERSION = "0.0.1"
3
+ end
data/lib/foot_stats.rb ADDED
@@ -0,0 +1,14 @@
1
+ require 'foot_stats/version'
2
+
3
+ module FootStats
4
+ autoload :Championship, 'foot_stats/championship'
5
+ autoload :ChampionshipClassification, 'foot_stats/championship_classification'
6
+ autoload :ErrorResponse, 'foot_stats/error_response'
7
+ autoload :Match, 'foot_stats/match'
8
+ autoload :Narration, 'foot_stats/narration'
9
+ autoload :Resource, 'foot_stats/resource'
10
+ autoload :Request, 'foot_stats/request'
11
+ autoload :Response, 'foot_stats/response'
12
+ autoload :Team, 'foot_stats/team'
13
+ autoload :Setup, 'foot_stats/setup'
14
+ end