ehbrs_ruby_utils 0.22.0 → 0.23.0

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 (32) hide show
  1. checksums.yaml +4 -4
  2. data/lib/ehbrs_ruby_utils/bga/parsers/game_stats/players.rb +25 -0
  3. data/lib/ehbrs_ruby_utils/bga/parsers/game_stats.rb +47 -0
  4. data/lib/ehbrs_ruby_utils/bga/parsers/table/options.rb +31 -0
  5. data/lib/ehbrs_ruby_utils/bga/parsers/table/players.rb +28 -0
  6. data/lib/ehbrs_ruby_utils/bga/parsers/table.rb +41 -0
  7. data/lib/ehbrs_ruby_utils/bga/session/login.rb +62 -0
  8. data/lib/ehbrs_ruby_utils/bga/session/player.rb +28 -0
  9. data/lib/ehbrs_ruby_utils/bga/session/table.rb +39 -0
  10. data/lib/ehbrs_ruby_utils/bga/session.rb +28 -0
  11. data/lib/ehbrs_ruby_utils/bga/table/option.rb +20 -0
  12. data/lib/ehbrs_ruby_utils/bga/table/player.rb +20 -0
  13. data/lib/ehbrs_ruby_utils/bga/table.rb +41 -0
  14. data/lib/ehbrs_ruby_utils/bga/urls.rb +34 -0
  15. data/lib/ehbrs_ruby_utils/executables.rb +5 -0
  16. data/lib/ehbrs_ruby_utils/version.rb +1 -1
  17. data/spec/lib/ehbrs_ruby_utils/bga/parsers/game_stats_spec.rb +7 -0
  18. data/spec/lib/ehbrs_ruby_utils/bga/parsers/game_stats_spec_files/1.source.html +1082 -0
  19. data/spec/lib/ehbrs_ruby_utils/bga/parsers/game_stats_spec_files/1.target.yaml +151 -0
  20. data/spec/lib/ehbrs_ruby_utils/bga/parsers/table_spec.rb +7 -0
  21. data/spec/lib/ehbrs_ruby_utils/bga/parsers/table_spec_files/table_302873643.source.html +1491 -0
  22. data/spec/lib/ehbrs_ruby_utils/bga/parsers/table_spec_files/table_302873643.target.yaml +34 -0
  23. data/spec/lib/ehbrs_ruby_utils/bga/parsers/table_spec_files/table_357408039.source.html +1500 -0
  24. data/spec/lib/ehbrs_ruby_utils/bga/parsers/table_spec_files/table_357408039.target.yaml +54 -0
  25. data/spec/lib/ehbrs_ruby_utils/bga/parsers/table_spec_files/table_368448439.source.html +1497 -0
  26. data/spec/lib/ehbrs_ruby_utils/bga/parsers/table_spec_files/table_368448439.target.yaml +48 -0
  27. data/spec/lib/ehbrs_ruby_utils/bga/parsers/table_spec_files/table_373602409.source.html +1441 -0
  28. data/spec/lib/ehbrs_ruby_utils/bga/parsers/table_spec_files/table_373602409.target.yaml +24 -0
  29. data/spec/lib/ehbrs_ruby_utils/bga/parsers/table_spec_files/table_373747455.source.html +1521 -0
  30. data/spec/lib/ehbrs_ruby_utils/bga/parsers/table_spec_files/table_373747455.target.yaml +53 -0
  31. data/spec/lib/ehbrs_ruby_utils/circular_list_spreader_spec.rb +4 -2
  32. metadata +59 -24
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2a241af9b0a27b447cef66e7d719fbda116547b7cfe5ceac348b9bb1bd5662d9
4
- data.tar.gz: b02d61f6840f2a602535c24c655bc6a5655a6daa531995a9d78523165517c066
3
+ metadata.gz: 90c029952b15c0fa9fd3034c5766583e9f8679c8efd16a005304ede77774b1ee
4
+ data.tar.gz: 8862eaf9b276fd42e92856ea98fa42e38d991c5e3c825ec1e1474ebaaaddefc6
5
5
  SHA512:
6
- metadata.gz: 54762c964c78d7335f8efc92b19c29b6b7281a37d473e1b3cdd5515177e3e54492808c84481ce075c6a758c3d5d6ccb1fe1ad07ca5d75512600cb026a605697d
7
- data.tar.gz: bf4f9ea658f93e2285735d98f22dde951a921f8d7f271b16c5d91c677119ef4c1f6c5f073427b30a4dc7b8dd207fe3bea2b05b00db0af76558b6e21cd246ec60
6
+ metadata.gz: fbc869e81f0a95f04cf9a393eb4f6f9b1d79e3d77ac3ff9f720b3115722adf41fbe6478e9c7d9878b297c8c46342686ce79a11fceb2f8b5d52c197044724372b
7
+ data.tar.gz: aab5320864d3863cc32878679ae7ee7cfa84610ed24bd0ade989c60a20a3285fb0a348efeb2aafc7eed71bf824c1ff6ee7dcc2c12467ab5efbd89722f058474f
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'aranha/parsers/html/item_list'
4
+ require 'eac_ruby_utils/core_ext'
5
+
6
+ module EhbrsRubyUtils
7
+ module Bga
8
+ module Parsers
9
+ class GameStats < ::Aranha::Parsers::Html::ItemList
10
+ class Players < ::Aranha::Parsers::Html::ItemList
11
+ ITEMS_XPATH = '//div[@class = "simple-score-entry"]'
12
+
13
+ field :rank, :integer, './div[@class = "rank"]'
14
+ field :id, :integer, './div[@class = "name"]/a/@href'
15
+ field :name, :string, './div[@class = "name"]/a/text()'
16
+ field :score, :integer, './div[@class = "score"]'
17
+
18
+ def items_xpath
19
+ ITEMS_XPATH
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'aranha/parsers/html/item_list'
4
+ require 'eac_ruby_utils/core_ext'
5
+
6
+ module EhbrsRubyUtils
7
+ module Bga
8
+ module Parsers
9
+ class GameStats < ::Aranha::Parsers::Html::ItemList
10
+ ITEMS_XPATH = '//table[@id = "gamelist_inner"]/tr'
11
+
12
+ field :game_name, :string, './td[1]/a[1]/text()'
13
+ field :table_name, :string, './td[1]/a[2]/text()'
14
+ field :time_string, :string, './td[2]/div[1]/text()'
15
+ field :leave_penalty, :integer, './td[4]/span[1]/text()'
16
+ field :rank_increment, :integer, './td[4]/span[2]/text()'
17
+ field :rank_after, :integer, './td[4]//*[@class = "gamerank_value"]/text()'
18
+ field :players, :node, './td[3]'
19
+
20
+ def items_xpath
21
+ ITEMS_XPATH
22
+ end
23
+
24
+ def item_data(item)
25
+ r = super
26
+ r[:table_id] = table_name_to_id(r.delete(:table_name))
27
+ r[:players] = players_data(r.delete(:players))
28
+ r
29
+ end
30
+
31
+ private
32
+
33
+ def players_data(players_node)
34
+ ::EhbrsRubyUtils::Bga::Parsers::GameStats::Players.from_node(
35
+ players_node
36
+ ).data
37
+ end
38
+
39
+ def table_name_to_id(name)
40
+ name.gsub(/\A\#/, '')
41
+ end
42
+
43
+ require_sub __FILE__
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'aranha/parsers/html/item'
4
+ require 'aranha/parsers/html/item_list'
5
+ require 'eac_ruby_utils/core_ext'
6
+
7
+ module EhbrsRubyUtils
8
+ module Bga
9
+ module Parsers
10
+ class Table < ::Aranha::Parsers::Html::Item
11
+ class Options < ::Aranha::Parsers::Html::ItemList
12
+ ITEMS_XPATH = '//div[starts-with(@id, "gameoption_")' \
13
+ ' and not(contains(@style, "none"))]'
14
+
15
+ field :label, :string, './div[@class = "row-label"]/text()'
16
+ field :value, :string, './div[@class = "row-value"]' \
17
+ "//*[#{xpath_ends_with('@id', "'_displayed_value'")}]/text()"
18
+ field :description, :string, './div[@class = "gameoption_description"]/text()'
19
+
20
+ def items_xpath
21
+ ITEMS_XPATH
22
+ end
23
+
24
+ def data
25
+ super.reject { |item| item.fetch(:label).blank? }
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'aranha/parsers/html/item'
4
+ require 'aranha/parsers/html/item_list'
5
+ require 'eac_ruby_utils/core_ext'
6
+
7
+ module EhbrsRubyUtils
8
+ module Bga
9
+ module Parsers
10
+ class Table < ::Aranha::Parsers::Html::Item
11
+ class Players < ::Aranha::Parsers::Html::ItemList
12
+ ITEMS_XPATH = '//div[starts-with(@id, "score_entry_")]'
13
+
14
+ field :table_rank, :integer, './div[@class = "rank"]'
15
+ field :id, :integer, './div[@class = "name"]/a/@href'
16
+ field :name, :string, './div[@class = "name"]/a/text()'
17
+ field :score, :integer, './div[@class = "score"]'
18
+ field :win_points, :string, './/*[starts-with(@id, "winpoints_value_")]/text()'
19
+ field :game_rank, :integer, './/*[@class = "gamerank_value"]/text()'
20
+
21
+ def items_xpath
22
+ ITEMS_XPATH
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'aranha/parsers/html/item'
4
+ require 'eac_ruby_utils/core_ext'
5
+
6
+ module EhbrsRubyUtils
7
+ module Bga
8
+ module Parsers
9
+ class Table < ::Aranha::Parsers::Html::Item
10
+ ITEM_XPATH = '/'
11
+
12
+ field :game_name, :string, './/*[@id = "table_name"]/text()'
13
+ field :creation_time, :string, './/*[@id = "creationtime"]/text()'
14
+ field :estimated_duration, :string, './/*[@id = "estimated_duration"]/text()'
15
+ field :options, :node, './/*[@id = "gameoptions"]'
16
+ field :players, :node, './/*[@id = "game_result"]'
17
+
18
+ def item_xpath
19
+ ITEM_XPATH
20
+ end
21
+
22
+ def data
23
+ r = super
24
+ %i[options players].each do |key|
25
+ r[key] = self.class.const_get(key.to_s.camelize).from_node(r.fetch(key)).data
26
+ end
27
+ r[:creation_time] = process_creation_time(r[:creation_time])
28
+ r
29
+ end
30
+
31
+ private
32
+
33
+ def process_creation_time(creation_time)
34
+ creation_time.gsub('Criado:', '').strip
35
+ end
36
+
37
+ require_sub __FILE__
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'eac_ruby_utils/core_ext'
4
+
5
+ module EhbrsRubyUtils
6
+ module Bga
7
+ class Session < ::SimpleDelegator
8
+ module Login
9
+ LOGIN_PATH = 'account'
10
+ USERNAME_INPUT_ID = 'username_input'
11
+ PASSWORD_INPUT_ID = 'password_input'
12
+ SUBMIT_ID = 'login_button'
13
+ LOGGED_MESSAGE_PATTERNS = [
14
+ /Page not found/ # Page not found: join.js
15
+ ].freeze
16
+ UNLOGGED_MESSAGE_PATTERSN = [
17
+ /Recover my password/ # Oops, we don't recognize your username or password. Don't panic.
18
+ # (Recover my password)
19
+ ].freeze
20
+
21
+ # @return [Boolean]
22
+ def login
23
+ navigate_to_login_page
24
+ input_username
25
+ input_password
26
+ submit_login
27
+ logged_by_message?(message_info)
28
+ end
29
+
30
+ def login_url
31
+ build_url(LOGIN_PATH)
32
+ end
33
+
34
+ private
35
+
36
+ def navigate_to_login_page
37
+ navigate.to(login_url)
38
+ end
39
+
40
+ def input_username
41
+ wait_for_element(id: USERNAME_INPUT_ID).send_keys(username)
42
+ end
43
+
44
+ def input_password
45
+ wait_for_element(id: PASSWORD_INPUT_ID).send_keys(password)
46
+ end
47
+
48
+ def submit_login
49
+ wait_for_click(id: SUBMIT_ID)
50
+ end
51
+
52
+ # @return [Boolean]
53
+ def logged_by_message?(message_info)
54
+ return true if LOGGED_MESSAGE_PATTERNS.any? { |p| p.match?(message_info) }
55
+ return false if UNLOGGED_MESSAGE_PATTERNS.any? { |p| p.match?(message_info) }
56
+
57
+ raise("Unmapped login message: \"#{message_info}\"")
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ehbrs_ruby_utils/bga/parsers/game_stats'
4
+ require 'ehbrs_ruby_utils/bga/urls'
5
+ require 'eac_ruby_utils/core_ext'
6
+
7
+ module EhbrsRubyUtils
8
+ module Bga
9
+ class Session < ::SimpleDelegator
10
+ class Player
11
+ include ::EhbrsRubyUtils::Bga::Urls
12
+ GAME_HISTORY_XPATH = '//h3[text() = "Games history"]'
13
+ common_constructor :session, :player_id
14
+
15
+ def tables
16
+ session.navigate.to game_stats_url
17
+ session.wait_for_element(xpath: GAME_HISTORY_XPATH)
18
+ ::EhbrsRubyUtils::Bga::Parsers::GameStats.from_content(session.current_source).data
19
+ end
20
+
21
+ # @return [Addressable::URI]
22
+ def game_stats_url
23
+ session.url("/gamestats?player=#{player_id}")
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ehbrs_ruby_utils/bga/parsers/table'
4
+ require 'ehbrs_ruby_utils/bga/table'
5
+ require 'ehbrs_ruby_utils/bga/urls'
6
+ require 'eac_ruby_utils/core_ext'
7
+
8
+ module EhbrsRubyUtils
9
+ module Bga
10
+ class Session < ::SimpleDelegator
11
+ class Table
12
+ include ::EhbrsRubyUtils::Bga::Urls
13
+ enable_method_class
14
+ enable_simple_cache
15
+ common_constructor :session, :table_id
16
+
17
+ def result
18
+ ::EhbrsRubyUtils::Bga::Table.new(
19
+ fetch_data
20
+ )
21
+ end
22
+
23
+ # @return [Addressable::URI]
24
+ def url
25
+ table_url(table_id)
26
+ end
27
+
28
+ private
29
+
30
+ def fetch_data
31
+ session.navigate.to url
32
+ { id: table_id }.merge(
33
+ ::EhbrsRubyUtils::Bga::Parsers::Table.from_content(session.current_source).data
34
+ )
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'aranha/selenium/session'
4
+ require 'eac_ruby_utils/core_ext'
5
+ require 'ehbrs_ruby_utils/bga/urls'
6
+
7
+ module EhbrsRubyUtils
8
+ module Bga
9
+ class Session < ::SimpleDelegator
10
+ include ::EhbrsRubyUtils::Bga::Urls
11
+ MESSAGE_ID = 'head_infomsg_1'
12
+
13
+ common_constructor :username, :password, super_args: -> { [::Aranha::Selenium::Session.new] }
14
+
15
+ # @return [String]
16
+ def message_info
17
+ wait_for_click(id: MESSAGE_ID).text
18
+ end
19
+
20
+ # @return [EhbrsRubyUtils::Bga::Session::Player]
21
+ def player(id)
22
+ ::EhbrsRubyUtils::Bga::Session::Player.new(self, id)
23
+ end
24
+
25
+ require_sub __FILE__, include_modules: true, require_mode: :kernel
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ehbrs_ruby_utils/bga/parsers/table/options'
4
+ require 'eac_ruby_utils/core_ext'
5
+
6
+ module EhbrsRubyUtils
7
+ module Bga
8
+ class Table
9
+ class Option
10
+ common_constructor :table, :data
11
+
12
+ ::EhbrsRubyUtils::Bga::Parsers::Table::Options.fields.each do |field|
13
+ define_method field.name do
14
+ data.fetch(field.name)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ehbrs_ruby_utils/bga/parsers/table/players'
4
+ require 'eac_ruby_utils/core_ext'
5
+
6
+ module EhbrsRubyUtils
7
+ module Bga
8
+ class Table
9
+ class Player
10
+ common_constructor :table, :data
11
+
12
+ ::EhbrsRubyUtils::Bga::Parsers::Table::Players.fields.each do |field|
13
+ define_method field.name do
14
+ data.fetch(field.name)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ehbrs_ruby_utils/bga/parsers/table/options'
4
+ require 'ehbrs_ruby_utils/bga/urls'
5
+ require 'eac_ruby_utils/core_ext'
6
+
7
+ module EhbrsRubyUtils
8
+ module Bga
9
+ class Table
10
+ include ::EhbrsRubyUtils::Bga::Urls
11
+ enable_simple_cache
12
+ common_constructor :data
13
+
14
+ SET_ITEMS = %i[options players].freeze
15
+
16
+ ([:id] + ::EhbrsRubyUtils::Bga::Parsers::Table.fields.map(&:name) - SET_ITEMS)
17
+ .each do |field|
18
+ define_method field do
19
+ data.fetch(field)
20
+ end
21
+ end
22
+
23
+ # @return [Addressable::URI]
24
+ def url
25
+ table_url(id)
26
+ end
27
+
28
+ private
29
+
30
+ SET_ITEMS.each do |item|
31
+ define_method "#{item}_uncached" do
32
+ data.fetch(item).map do |item_data|
33
+ self.class.const_get(item.to_s.singularize.camelize).new(self, item_data)
34
+ end
35
+ end
36
+ end
37
+
38
+ require_sub __FILE__
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'aranha/selenium/session'
4
+ require 'eac_ruby_utils/core_ext'
5
+
6
+ module EhbrsRubyUtils
7
+ module Bga
8
+ module Urls
9
+ common_concern
10
+
11
+ module InstanceMethods
12
+ ROOT_URL = 'https://en.boardgamearena.com'
13
+
14
+ # @param suffix [String]
15
+ # @return [Addressable::URI]
16
+ def build_url(suffix)
17
+ root_url + suffix
18
+ end
19
+
20
+ # @return [Addressable::URI]
21
+ def root_url
22
+ ROOT_URL.to_uri
23
+ end
24
+
25
+ # @return [Addressable::URI]
26
+ def table_url(table_id)
27
+ build_url("/table?table=#{table_id}")
28
+ end
29
+ end
30
+
31
+ extend InstanceMethods
32
+ end
33
+ end
34
+ end
@@ -23,6 +23,11 @@ module EhbrsRubyUtils
23
23
  end
24
24
  end
25
25
  end
26
+
27
+ # @return [EacRubyUtils::Envs::Executable]
28
+ def mudslide_uncached
29
+ env.executable('mudslide', exec_args: %w[npx mudslide@latest], check_args: %w[--version])
30
+ end
26
31
  end
27
32
  end
28
33
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module EhbrsRubyUtils
4
- VERSION = '0.22.0'
4
+ VERSION = '0.23.0'
5
5
  end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ehbrs_ruby_utils/bga/parsers/game_stats'
4
+
5
+ ::RSpec.describe ::EhbrsRubyUtils::Bga::Parsers::GameStats do
6
+ include_examples 'source_target_fixtures', __FILE__
7
+ end