kakuyomu_agent 0.1.0 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 15e9b3078d627199445d9d6591c88114143d245740ac7448c06dfe03b75bf668
4
- data.tar.gz: fee06253f5b28622efb18277c15a6b232a5cc413d81e09e4f02d59c4f5f3f983
3
+ metadata.gz: 5402095c5853b227b4f10d74fdb79430e6352af2b5a005c3a89ad5ab2a317714
4
+ data.tar.gz: 5e309384fb7094fb5a74203fd605e33c4d3150fd8d16dbc76aded9d3179f830a
5
5
  SHA512:
6
- metadata.gz: 779b6da5f1ded127de3e618e2957c791c00601848bdc1315dd93a5ca1a4a64aea7997e39372660b58162867e2c69275f9a518489f9c429c4937697709711c8e7
7
- data.tar.gz: dcd128af4875b98da9f58adf24a968ecc4998f026498126285434170afb5b8d101432ddd4e5cb9661997dd0c0e91b6269fb832a181bc8064fa92e21f63ff610c
6
+ metadata.gz: 455b5695ee51d1a9c231292cc4249cf58df425abd590c1cfd0ca530fd5d34d7815759cfc223f92f2b305088b0727942b0bb1af7525979be5563220e37441a429
7
+ data.tar.gz: c4ee9b0911c4fe852cea0a79454afe37839f7de58d9cd3546f7ca73866e314ef9def5ee2881d491db1db3fb1d45c76f49fe7c727af99c2f8f38ee565863987b0
data/README.md CHANGED
@@ -23,16 +23,19 @@ Or install it yourself as:
23
23
  ```ruby
24
24
  require 'kakuyomu_agent'
25
25
 
26
- agent = KakuyomuAgent.new
26
+ agent = KakuyomuAgent.new(driver: Selenium::WebDriver.for(:chrome))
27
27
 
28
28
  # ログイン
29
29
  agent.login!(email: YOUR_EMAIL, password: YOUR_PASSWORD)
30
30
 
31
31
  # 小説の URL から work_id を抽出
32
- work_id = KakuyomuAgent::UrlUtils.extract_work_id('https://kakuyomu.jp/works/1234567890123456789') # => 1234567890123456789
32
+ work_id = KakuyomuAgent::UrlHelper.extract_work_id('https://kakuyomu.jp/works/1234567890123456789') # => 1234567890123456789
33
33
 
34
34
  # エピソードを執筆
35
- episode_id = agent.create_episode(work_id: work_id, title: 'タイトル', body: '本文')
35
+ episode_url = agent.create_episode(work_id: work_id, title: 'タイトル', body: '本文')
36
+
37
+ # エピソードの URL から episode_id を抽出
38
+ episode_id = KakuyomuAgent::UrlHelper.extract_episode_id(episode_url)
36
39
 
37
40
  # エピソードを編集
38
41
  agent.update_episode(work_id: work_id, episode_id: episode_id, title: '新しいタイトル', body: '新しい本文')
@@ -1,12 +1,16 @@
1
1
  require 'selenium-webdriver'
2
2
 
3
- require_relative 'kakuyomu_agent/url_utils'
3
+ require_relative 'kakuyomu_agent/url_helper'
4
+ require_relative 'kakuyomu_agent/action'
5
+ require_relative 'kakuyomu_agent/error'
4
6
  require_relative 'kakuyomu_agent/version'
5
7
 
6
- class KakuyomuAgent
7
- Error = Class.new(StandardError)
8
- NotLoggedInError = Class.new(Error)
8
+ require_relative 'kakuyomu_agent/actions/create_episode'
9
+ require_relative 'kakuyomu_agent/actions/delete_episode'
10
+ require_relative 'kakuyomu_agent/actions/login'
11
+ require_relative 'kakuyomu_agent/actions/update_episode'
9
12
 
13
+ class KakuyomuAgent
10
14
  BASE_URL = 'https://kakuyomu.jp'
11
15
 
12
16
  attr_reader :base_url, :driver
@@ -22,101 +26,22 @@ class KakuyomuAgent
22
26
  end
23
27
 
24
28
  def login!(email:, password:)
25
- driver.navigate.to(login_url)
26
- driver.find_element(name: 'email_address').send_keys(email)
27
- driver.find_element(name: 'password').send_keys(password)
28
- driver.find_element(xpath: '//button[text()="ログイン"]').click
29
-
30
- Selenium::WebDriver::Wait.new.until do
31
- driver.find_element(id: 'page-my')
32
- end
33
-
29
+ Actions::Login.new(self).run(email, password)
34
30
  @logged_in = true
35
- rescue Selenium::WebDriver::Error::WebDriverError => e
36
- raise Error, "Logging in failed: #{e.message}"
37
31
  end
38
32
 
39
33
  def create_episode(work_id:, title:, body:)
40
34
  raise NotLoggedInError unless logged_in?
41
-
42
- driver.navigate.to(new_episode_url(work_id))
43
-
44
- title_input = driver.find_element(name: 'title')
45
- title_input.clear
46
- title_input.send_keys(title)
47
-
48
- driver.find_element(name: 'body').send_keys(body)
49
-
50
- driver.find_element(id: 'reserveButton').click
51
- driver.find_element(id: 'reservationControl-footer').find_element(tag_name: 'button').click
52
-
53
- Selenium::WebDriver::Wait.new.until do
54
- driver.find_element(id: 'page-my-works-episodes-published')
55
- end
56
-
57
- episode_id = UrlUtils.extract_episode_id(driver.current_url)
58
- episode_url(work_id, episode_id)
59
- rescue Selenium::WebDriver::Error::WebDriverError => e
60
- raise Error, "Creating episode failed: #{e.message}"
35
+ Actions::CreateEpisode.new(self).run(work_id, title, body)
61
36
  end
62
37
 
63
38
  def update_episode(work_id:, episode_id:, title:, body:)
64
39
  raise NotLoggedInError unless logged_in?
65
-
66
- driver.navigate.to(edit_episode_url(work_id, episode_id))
67
-
68
- title_input = driver.find_element(name: 'title')
69
- title_input.clear
70
- title_input.send_keys(title)
71
-
72
- body_textarea = driver.find_element(name: 'body')
73
- body_textarea.clear
74
- body_textarea.send_keys(body)
75
-
76
- driver.find_element(id: 'updateButton').click
77
-
78
- Selenium::WebDriver::Wait.new.until do
79
- driver.find_element(id: 'page-my-works-episodes-published')
80
- end
81
-
82
- episode_url(work_id, episode_id)
83
- rescue Selenium::WebDriver::Error::WebDriverError => e
84
- raise Error, "Updating episode failed: #{e.message}"
40
+ Actions::UpdateEpisode.new(self).run(work_id, episode_id, title, body)
85
41
  end
86
42
 
87
43
  def delete_episode(work_id:, episode_id:)
88
44
  raise NotLoggedInError unless logged_in?
89
-
90
- driver.navigate.to(edit_episode_url(work_id, episode_id))
91
- driver.find_element(id: 'contentMainHeader-toolButton').click
92
- driver.find_element(id: 'contentAsideHeader').find_element(xpath: '//*[contains(text(), "ツール")]').click
93
- driver.find_element(id: 'deleteEpisode').find_element(tag_name: 'button').click
94
- driver.switch_to.alert.accept
95
-
96
- Selenium::WebDriver::Wait.new.until do
97
- driver.find_element(id: 'modelessMessage')
98
- end
99
-
100
- true
101
- rescue Selenium::WebDriver::Error::WebDriverError => e
102
- raise Error, "Deleting episode failed: #{e.message}"
103
- end
104
-
105
- private
106
-
107
- def login_url
108
- "#{base_url}/login"
109
- end
110
-
111
- def episode_url(work_id, episode_id)
112
- "#{base_url}/works/#{work_id}/episodes/#{episode_id}"
113
- end
114
-
115
- def new_episode_url(work_id)
116
- "#{base_url}/my/works/#{work_id}/episodes/new"
117
- end
118
-
119
- def edit_episode_url(work_id, episode_id)
120
- "#{base_url}/my/works/#{work_id}/episodes/#{episode_id}"
45
+ Actions::DeleteEpisode.new(self).run(work_id, episode_id)
121
46
  end
122
47
  end
@@ -0,0 +1,16 @@
1
+ class KakuyomuAgent
2
+ class Action
3
+ include UrlHelper
4
+ extend Forwardable
5
+
6
+ def_delegators :@agent, :base_url, :driver
7
+
8
+ def initialize(agent)
9
+ @agent = agent
10
+ end
11
+
12
+ def run
13
+ raise NotImplementedError
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,27 @@
1
+ class KakuyomuAgent
2
+ module Actions
3
+ class CreateEpisode < Action
4
+ def run(work_id, title, body)
5
+ driver.get(new_episode_url(work_id))
6
+
7
+ title_input = driver.find_element(name: 'title')
8
+ title_input.clear
9
+ title_input.send_keys(title)
10
+
11
+ driver.find_element(name: 'body').send_keys(body)
12
+
13
+ driver.find_element(id: 'reserveButton').click
14
+ driver.find_element(id: 'reservationControl-footer').find_element(tag_name: 'button').click
15
+
16
+ Selenium::WebDriver::Wait.new.until do
17
+ driver.find_element(id: 'page-my-works-episodes-published')
18
+ end
19
+
20
+ episode_id = UrlHelper.extract_episode_id(driver.current_url)
21
+ episode_url(work_id, episode_id)
22
+ rescue Selenium::WebDriver::Error::WebDriverError => e
23
+ raise ActionFailedError.new(e)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,22 @@
1
+ class KakuyomuAgent
2
+ module Actions
3
+ class DeleteEpisode < Action
4
+ def run(work_id, episode_id)
5
+ driver.get(edit_episode_url(work_id, episode_id))
6
+
7
+ driver.find_element(id: 'contentMainHeader-toolButton').click
8
+ driver.find_element(id: 'contentAsideHeader').find_element(xpath: '//*[contains(text(), "ツール")]').click
9
+ driver.find_element(id: 'deleteEpisode').find_element(tag_name: 'button').click
10
+ driver.switch_to.alert.accept
11
+
12
+ Selenium::WebDriver::Wait.new.until do
13
+ driver.find_element(id: 'modelessMessage')
14
+ end
15
+
16
+ true
17
+ rescue Selenium::WebDriver::Error::WebDriverError => e
18
+ raise ActionFailedError.new(e)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,20 @@
1
+ class KakuyomuAgent
2
+ module Actions
3
+ class Login < Action
4
+ def run(email, password)
5
+ driver.get(login_url)
6
+
7
+ driver.find_element(name: 'email_address').send_keys(email)
8
+ driver.find_element(name: 'password').send_keys(password)
9
+
10
+ driver.find_element(xpath: '//button[text()="ログイン"]').click
11
+
12
+ Selenium::WebDriver::Wait.new.until do
13
+ driver.find_element(id: 'page-my')
14
+ end
15
+ rescue Selenium::WebDriver::Error::WebDriverError => e
16
+ raise ActionFailedError.new(e)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,27 @@
1
+ class KakuyomuAgent
2
+ module Actions
3
+ class UpdateEpisode < Action
4
+ def run(work_id, episode_id, title, body)
5
+ driver.get(edit_episode_url(work_id, episode_id))
6
+
7
+ title_input = driver.find_element(name: 'title')
8
+ title_input.clear
9
+ title_input.send_keys(title)
10
+
11
+ body_textarea = driver.find_element(name: 'body')
12
+ body_textarea.clear
13
+ body_textarea.send_keys(body)
14
+
15
+ driver.find_element(id: 'updateButton').click
16
+
17
+ Selenium::WebDriver::Wait.new.until do
18
+ driver.find_element(id: 'page-my-works-episodes-published')
19
+ end
20
+
21
+ episode_url(work_id, episode_id)
22
+ rescue Selenium::WebDriver::Error::WebDriverError => e
23
+ raise ActionFailedError.new(e)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,5 @@
1
+ class KakuyomuAgent
2
+ Error = Class.new(StandardError)
3
+ NotLoggedInError = Class.new(Error)
4
+ ActionFailedError = Class.new(Error)
5
+ end
@@ -0,0 +1,31 @@
1
+ class KakuyomuAgent
2
+ module UrlHelper
3
+ class << self
4
+ def extract_work_id(url)
5
+ url[%r{works/(\d+)}, 1]
6
+ end
7
+
8
+ def extract_episode_id(url)
9
+ url[%r{episodes/(\d+)}, 1]
10
+ end
11
+ end
12
+
13
+ private
14
+
15
+ def login_url
16
+ "#{base_url}/login"
17
+ end
18
+
19
+ def episode_url(work_id, episode_id)
20
+ "#{base_url}/works/#{work_id}/episodes/#{episode_id}"
21
+ end
22
+
23
+ def new_episode_url(work_id)
24
+ "#{base_url}/my/works/#{work_id}/episodes/new"
25
+ end
26
+
27
+ def edit_episode_url(work_id, episode_id)
28
+ "#{base_url}/my/works/#{work_id}/episodes/#{episode_id}"
29
+ end
30
+ end
31
+ end
@@ -1,3 +1,3 @@
1
1
  class KakuyomuAgent
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kakuyomu_agent
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fuji Nakahara
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-11-10 00:00:00.000000000 Z
11
+ date: 2018-11-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: selenium-webdriver
@@ -129,7 +129,13 @@ files:
129
129
  - bin/setup
130
130
  - kakuyomu_agent.gemspec
131
131
  - lib/kakuyomu_agent.rb
132
- - lib/kakuyomu_agent/url_utils.rb
132
+ - lib/kakuyomu_agent/action.rb
133
+ - lib/kakuyomu_agent/actions/create_episode.rb
134
+ - lib/kakuyomu_agent/actions/delete_episode.rb
135
+ - lib/kakuyomu_agent/actions/login.rb
136
+ - lib/kakuyomu_agent/actions/update_episode.rb
137
+ - lib/kakuyomu_agent/error.rb
138
+ - lib/kakuyomu_agent/url_helper.rb
133
139
  - lib/kakuyomu_agent/version.rb
134
140
  homepage: https://github.com/fuji-nakahara/kakuyomu_agent
135
141
  licenses:
@@ -1,13 +0,0 @@
1
- class KakuyomuAgent
2
- module UrlUtils
3
- class << self
4
- def extract_work_id(url)
5
- url[%r{works/(\d+)}, 1]
6
- end
7
-
8
- def extract_episode_id(url)
9
- url[%r{episodes/(\d+)}, 1]
10
- end
11
- end
12
- end
13
- end