kobot 1.2.2 → 1.3.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: c5280569d35d3db17de90830bc1b6b2fa7fd4ec17c1b3efae0772a2329288fbe
4
- data.tar.gz: 51a08ceb2e07e577a503e6c5bbd17352e664612a9b6ae6fd6e3ca9aedc56a71e
3
+ metadata.gz: '08261437cd35a8b09dfad79740f2f6ec52e87fea47713aba5e00133aa570ac08'
4
+ data.tar.gz: a7941208f88d46d40fb8d5366851f5b466bb85e975b3d5ff95e7753bf9f8032c
5
5
  SHA512:
6
- metadata.gz: 9ce2200116a9c36f384edbc2a0a2b47b37819ddb44fb8f590a1a1af1afd0859ea4d56c2022c4990f720f9bbd42eb4aaaf26986333298ed61580a4ad37b41bbed
7
- data.tar.gz: 783cd8e9c729404108119fc2c26b49729852c68e40e415dad7d5ab92066021a4c2496fe3aaeab355911ad174b848af1cda99510496a53ff282f5d4fa42f8d244
6
+ metadata.gz: f14ebacda3eaec90ae6f6e9f995821d3116599e2fdff2e19afcd546c43404f6453055d256828f4f549e07d5f3e08ac0ba4cbc1c6ee0e4b3739a02277b0285258
7
+ data.tar.gz: d42d8f45187cc512eb08b13d5c891cd7b0bf567a76bf55b49ffc089c240946f0345208b7586fecbd2a32c8e3f3855f22086913bed5c79152e3248e5db0692d75
data/CHANGELOG.md CHANGED
@@ -18,3 +18,18 @@
18
18
  ### v1.2.2
19
19
  - Improved login screen wait and logging
20
20
  - Applied fix for offenses about empty lines and long lines reported by Rubocop
21
+
22
+ ### v1.2.3
23
+ - Improved validation logic to skip running due to weekend or intentional skips
24
+ - Refactored engine by reducing methods length based on reports by Rubocop
25
+
26
+ ### v1.2.4
27
+ - Changed to use boolean values for validation instead of raising exceptions
28
+
29
+ ### v1.2.5
30
+ - Added I18n support for both English and Japanese KOT UI
31
+
32
+ ### v1.3.0
33
+ - Added config option (-a, --auto-skip-without) to enable automatic skipping based on schedule
34
+ - Replaced deprecated options with capabilities option in Selenium driver initialization
35
+ - Refactored scattered attr_accessors and reduced instance variables count reported by Rubocop
data/README.md CHANGED
@@ -62,6 +62,9 @@ Usage: kobot [options]
62
62
  -s, --skip [D1,D2,D3] Specify dates to skip clock in/out with date format YYYY-MM-DD and
63
63
  multiple values separated by comma, such as: 2020-05-01,2020-12-31;
64
64
  weekends and public holidays in Japan will be skipped by default
65
+ -a [SCHEDULE], Enable automatic skipping by reading schedule from the Time Card page;
66
+ --auto-skip-without skip today if the provided text is not contained in the schedule column
67
+ on the Time Card page; by default 裁量労働 is used
65
68
  -t, --to [TO] Email address to send notification to; by default it is sent to
66
69
  the same self email account used in SMTP config as the sender
67
70
  -n, --notify Enable email notification
data/lib/kobot/config.rb CHANGED
@@ -8,24 +8,21 @@ module Kobot
8
8
  attr_accessor :clock,
9
9
  :loglevel,
10
10
  :skip,
11
+ :auto_skip_without,
11
12
  :dryrun,
12
- :force
13
-
14
- attr_accessor :kot_url,
13
+ :force,
14
+ :kot_url,
15
15
  :kot_timezone_offset,
16
- :kot_date_format
17
-
18
- attr_accessor :gmail_notify_enabled,
16
+ :kot_date_format,
17
+ :gmail_notify_enabled,
19
18
  :gmail_notify_subject,
20
19
  :gmail_notify_to,
21
20
  :gmail_smtp_address,
22
- :gmail_smtp_port
23
-
24
- attr_accessor :browser_headless,
21
+ :gmail_smtp_port,
22
+ :browser_headless,
25
23
  :browser_geolocation,
26
- :browser_wait_timeout
27
-
28
- attr_accessor :credentials_file
24
+ :browser_wait_timeout,
25
+ :credentials_file
29
26
 
30
27
  def configure
31
28
  yield self
data/lib/kobot/engine.rb CHANGED
@@ -14,7 +14,7 @@ module Kobot
14
14
 
15
15
  # The entrance where the whole flow starts.
16
16
  #
17
- # It exits early if today is weekend or treated as holiday by
17
+ # It exits early if today is weekend or marked as to skip by
18
18
  # the #{Config.skip} specified from command line option --skip.
19
19
  #
20
20
  # Unexpected behavior such as record appearing as holiday on
@@ -24,26 +24,12 @@ module Kobot
24
24
  # System errors or any unknown exceptions occurred if any are
25
25
  # to be popped up and should be handled by the outside caller.
26
26
  def start
27
- if weekend?
28
- if Config.force
29
- Kobot.logger.info("[Force] should have exited: today=#{@today} is weekend")
30
- else
31
- Kobot.logger.info("Today=#{@today} is weekend")
32
- return
33
- end
34
- end
35
- if skip?
36
- Kobot.logger.info("Today=#{@today} is skipped as per: --skip=#{Config.skip}")
37
- return
38
- end
39
- unless %i[in out].include? Config.clock
40
- Kobot.logger.warn("Invalid clock operation: #{Config.clock}")
41
- return
42
- end
27
+ return unless should_run_today?
28
+
43
29
  launch_browser
44
30
  login
45
31
  read_today_record
46
- verify_today_record!
32
+ validate_today_record!
47
33
  if Config.clock == :in
48
34
  clock_in!
49
35
  else
@@ -68,12 +54,23 @@ module Kobot
68
54
  Mailer.send(clock_notify_message(status: e.message))
69
55
  logout
70
56
  ensure
71
- Kobot.logger.info('Close browser')
72
- @browser&.quit
57
+ close_browser
73
58
  end
74
59
 
75
60
  private
76
61
 
62
+ def should_run_today?
63
+ if skip?
64
+ Kobot.logger.warn("Today=#{@today} is skipped as per: --skip=#{Config.skip}")
65
+ return false
66
+ end
67
+ return true unless weekend?
68
+
69
+ Kobot.logger.info("[Force] should have exited: today=#{@today} is weekend") if Config.force
70
+ Kobot.logger.warn("Today=#{@today} is weekend") unless Config.force
71
+ Config.force
72
+ end
73
+
77
74
  def launch_browser
78
75
  prefs = {
79
76
  profile: {
@@ -84,15 +81,31 @@ module Kobot
84
81
  }
85
82
  options = Selenium::WebDriver::Chrome::Options.new(prefs: prefs)
86
83
  options.headless! if Config.browser_headless
87
- @browser = Selenium::WebDriver.for(:chrome, options: options)
84
+ caps = [
85
+ options
86
+ ]
87
+ @browser = Selenium::WebDriver.for(:chrome, capabilities: caps)
88
88
  @wait = Selenium::WebDriver::Wait.new(timeout: Config.browser_wait_timeout)
89
89
  Kobot.logger.info('Launch browser successful')
90
90
  end
91
91
 
92
+ def close_browser
93
+ return unless @browser
94
+
95
+ Kobot.logger.info('Close browser')
96
+ @browser.quit
97
+ end
98
+
92
99
  def login
93
100
  Kobot.logger.info("Navigate to: #{@top_url}")
94
101
  @browser.get @top_url
95
102
  @wait.until { @browser.find_element(id: 'modal_window') }
103
+ modal_title_element = @wait.until { @browser.find_element(css: '.modal-title') }
104
+ @selector = if modal_title_element.text.downcase.include? 'password'
105
+ Selector.en
106
+ else
107
+ Selector.ja
108
+ end
96
109
  Kobot.logger.info "Page title: #{@browser.title}"
97
110
  Kobot.logger.debug do
98
111
  "Login with id=#{Credential.kot_id} and password=#{Credential.kot_password}"
@@ -102,10 +115,14 @@ module Kobot
102
115
  @browser.find_element(css: 'div.btn-control-message').click
103
116
 
104
117
  Kobot.logger.info 'Login successful'
105
- @wait.until { @browser.find_element(id: 'notification_content').text.include?('データを取得しました') }
118
+ @wait.until do
119
+ @browser.find_element(id: 'notification_content').text.include?(@selector.login_success_notification_text)
120
+ end
106
121
  if Config.browser_geolocation
107
122
  begin
108
- @wait.until { @browser.find_element(id: 'location_area').text.include?('位置情報取得済み') }
123
+ @wait.until do
124
+ @browser.find_element(id: 'location_area').text.include?(@selector.location_area_notification_text)
125
+ end
109
126
  rescue StandardError => e
110
127
  Kobot.logger.warn "Get geolocation failed: #{e.message}"
111
128
  end
@@ -115,21 +132,21 @@ module Kobot
115
132
 
116
133
  def logout
117
134
  if @browser.current_url.include? 'admin'
118
- Kobot.logger.info('Logout from タイムカード page')
135
+ Kobot.logger.info('Logout from Time Card (タイムカード) page')
119
136
  @browser.find_element(css: 'div.htBlock-header_logoutButton').click
120
137
  else
121
- Kobot.logger.info('Logout from Myレコーダー page')
138
+ Kobot.logger.info('Logout from My Recorder (Myレコーダー) page')
122
139
  @wait.until { @browser.find_element(id: 'menu_icon') }.click
123
- @wait.until { @browser.find_element(link: 'ログアウト') }.click
140
+ @wait.until { @browser.find_element(link: @selector.logout_menu_link_text) }.click
124
141
  @browser.switch_to.alert.accept
125
142
  end
126
143
  Kobot.logger.info 'Logout successful'
127
144
  end
128
145
 
129
146
  def read_today_record
130
- Kobot.logger.info('Navigate to タイムカード page')
147
+ Kobot.logger.info('Navigate to Time Card (タイムカード) page')
131
148
  @wait.until { @browser.find_element(id: 'menu_icon') }.click
132
- @wait.until { @browser.find_element(link: 'タイムカード') }.click
149
+ @wait.until { @browser.find_element(link: @selector.time_card_menu_link_text) }.click
133
150
 
134
151
  time_table = @wait.until { @browser.find_element(css: 'div.htBlock-adjastableTableF_inner > table') }
135
152
  time_table.find_elements(css: 'tbody > tr').each do |tr|
@@ -137,83 +154,94 @@ module Kobot
137
154
  next unless date_cell.text.include? @today
138
155
 
139
156
  Kobot.logger.info('Reading today record')
140
- @kot_today = date_cell.text
141
- @kot_today_css_class = date_cell.attribute('class')
142
- @kot_today_type = tr.find_element(css: 'td.work_day_type').text
143
- @kot_today_clock_in = tr.find_element(
157
+ @kot_data = {}
158
+ @kot_data[:today] = date_cell.text
159
+ @kot_data[:today_css_class] = date_cell.attribute('class')
160
+ @kot_data[:today_type] = tr.find_element(css: 'td.work_day_type').text
161
+ @kot_data[:today_schedule] = tr.find_element(css: 'td.schedule').text
162
+ @kot_data[:today_clock_in] = tr.find_element(
144
163
  css: 'td.start_end_timerecord[data-ht-sort-index="START_TIMERECORD"]'
145
164
  ).text
146
- @kot_today_clock_out = tr.find_element(
165
+ @kot_data[:today_clock_out] = tr.find_element(
147
166
  css: 'td.start_end_timerecord[data-ht-sort-index="END_TIMERECORD"]'
148
167
  ).text
149
168
  Kobot.logger.debug do
150
169
  {
151
- kot_toay: @kot_today,
152
- kot_today_css_class: @kot_today_css_class,
153
- kot_today_type: @kot_today_type,
154
- kot_today_clock_in: @kot_today_clock_in,
155
- kot_today_clock_out: @kot_today_clock_out
170
+ kot_toay: @kot_data[:today],
171
+ kot_today_css_class: @kot_data[:today_css_class],
172
+ kot_today_type: @kot_data[:today_type],
173
+ kot_today_clock_in: @kot_data[:today_clock_in],
174
+ kot_today_clock_out: @kot_data[:today_clock_out]
156
175
  }
157
176
  end
158
177
  break
159
178
  end
160
179
  end
161
180
 
162
- def verify_today_record!
163
- raise KotRecordError, "Today=#{@today} is not found on kot" if @kot_today.strip.empty?
181
+ def validate_today_record!
182
+ raise KotRecordError, "Today=#{@today} is not found on kot" if @kot_data[:today].strip.empty?
164
183
 
165
184
  if kot_weekend?
166
- raise KotRecordError, "Today=#{@today} is marked as weekend on kot: #{@kot_today}" unless Config.force
185
+ raise KotRecordError, "Today=#{@today} is marked as weekend: #{@kot_data[:today]}" unless Config.force
186
+
187
+ Kobot.logger.info(
188
+ "[Force] should have exited: today=#{@today} is marked as weekend: #{@kot_data[:today]}"
189
+ )
190
+ end
191
+
192
+ if kot_public_holiday?
193
+ raise KotRecordError, "Today=#{@today} is marked as public holiday: #{@kot_data[:today]}" unless Config.force
167
194
 
168
195
  Kobot.logger.info(
169
- "[Force] should have exited: today=#{@today} is marked as weekend on kot: #{@kot_today}"
196
+ "[Force] should have exited: today=#{@today} is marked as public holiday: #{@kot_data[:today]}"
170
197
  )
171
198
  end
172
199
 
173
- return unless kot_public_holiday?
174
- raise KotRecordError, "Today=#{@today} is marked as public holiday on kot: #{@kot_today}" unless Config.force
200
+ if kot_non_work_schedule?
201
+ raise KotRecordError, "Today=#{@today} is non-work schedule: #{@kot_data[:today_schedule]}" unless Config.force
175
202
 
176
- Kobot.logger.info(
177
- "[Force] should have exited: today=#{@today} is marked as public holiday on kot: #{@kot_today}"
178
- )
203
+ Kobot.logger.info(
204
+ "[Force] should have exited: today=#{@today} is non-work schedule: #{@kot_data[:today_schedule]}"
205
+ )
206
+ end
179
207
  end
180
208
 
181
209
  def clock_in!
182
210
  Kobot.logger.warn("Clock in during the afternoon: #{@now}") if @now.hour > 12
183
- if @kot_today_clock_in.strip.empty?
211
+ if @kot_data[:today_clock_in].strip.empty?
184
212
  click_clock_in_button
185
213
  return if Config.dryrun
186
214
 
187
215
  read_today_record
188
- raise KotClockInError, 'Clock in operation seems to have failed' if @kot_today_clock_in.strip.empty?
216
+ raise KotClockInError, 'Clock in operation seems to have failed' if @kot_data[:today_clock_in].strip.empty?
189
217
 
190
- Kobot.logger.info("Clock in successful: #{@kot_today_clock_in}")
218
+ Kobot.logger.info("Clock in successful: #{@kot_data[:today_clock_in]}")
191
219
  Mailer.send(clock_notify_message(clock: :in))
192
220
  else
193
- Kobot.logger.warn("Clock in done already: #{@kot_today_clock_in}")
221
+ Kobot.logger.warn("Clock in done already: #{@kot_data[:today_clock_in]}")
194
222
  end
195
223
  end
196
224
 
197
225
  def clock_out!
198
226
  Kobot.logger.warn("Clock out during the morning: #{@now}") if @now.hour <= 12
199
227
  unless Config.dryrun
200
- if @kot_today_clock_in.strip.empty?
228
+ if @kot_data[:today_clock_in].strip.empty?
201
229
  raise KotClockOutError,
202
- "!!!No clock in record for today=#{@kot_today}!!!"
230
+ "!!!No clock in record for today=#{@kot_data[:today]}!!!"
203
231
  end
204
232
  end
205
233
 
206
- if @kot_today_clock_out.strip.empty?
234
+ if @kot_data[:today_clock_out].strip.empty?
207
235
  click_clock_out_button
208
236
  return if Config.dryrun
209
237
 
210
238
  read_today_record
211
- raise KotClockOutError, 'Clock out operation seems to have failed' if @kot_today_clock_out.strip.empty?
239
+ raise KotClockOutError, 'Clock out operation seems to have failed' if @kot_data[:today_clock_out].strip.empty?
212
240
 
213
- Kobot.logger.info("Clock out successful: #{@kot_today_clock_out}")
241
+ Kobot.logger.info("Clock out successful: #{@kot_data[:today_clock_out]}")
214
242
  Mailer.send(clock_notify_message(clock: :out))
215
243
  else
216
- Kobot.logger.warn("Clock out done already: #{@kot_today_clock_out}")
244
+ Kobot.logger.warn("Clock out done already: #{@kot_data[:today_clock_out]}")
217
245
  end
218
246
  end
219
247
 
@@ -222,9 +250,9 @@ module Kobot
222
250
  @browser.get @top_url
223
251
  clock_in_button = @wait.until { @browser.find_element(css: 'div.record-clock-in') }
224
252
  if Config.dryrun
225
- Kobot.logger.info('[Dryrun] clock in button (出勤) would have been clicked')
253
+ Kobot.logger.info('[Dryrun] Clock-in button (出勤) would have been clicked')
226
254
  else
227
- Kobot.logger.info('Clicking the clock in button (出勤)')
255
+ Kobot.logger.info('Clicking the Clock-in button (出勤)')
228
256
  clock_in_button.click
229
257
  end
230
258
  end
@@ -234,9 +262,9 @@ module Kobot
234
262
  @browser.get @top_url
235
263
  clock_out_button = @wait.until { @browser.find_element(css: 'div.record-clock-out') }
236
264
  if Config.dryrun
237
- Kobot.logger.info('[Dryrun] clock out button (退勤) would have been clicked')
265
+ Kobot.logger.info('[Dryrun] Clock-out button (退勤) would have been clicked')
238
266
  else
239
- Kobot.logger.info('Clicking the clock in button (退勤)')
267
+ Kobot.logger.info('Clicking the Clock-out button (退勤)')
240
268
  clock_out_button.click
241
269
  end
242
270
  end
@@ -253,18 +281,25 @@ module Kobot
253
281
  end
254
282
 
255
283
  def kot_weekend?
256
- %w[土 日].any? { |kanji| @kot_today&.include? kanji }
284
+ [
285
+ @selector.kot_date_saturday,
286
+ @selector.kot_date_sunday
287
+ ].any? { |weekend| @kot_data[:today]&.include? weekend }
288
+ end
289
+
290
+ def kot_non_work_schedule?
291
+ !@kot_data[:today_schedule]&.include?(Config.auto_skip_without)
257
292
  end
258
293
 
259
294
  def kot_public_holiday?
260
- return true if @kot_today_type&.include? '休日'
295
+ return true if @kot_data[:today_type]&.include? @selector.kot_workday_time_off_text
261
296
 
262
297
  kot_today_highlighted = %w[sunday saturday].any? do |css|
263
- @kot_today_css_class&.include? css
298
+ @kot_data[:today_css_class]&.include? css
264
299
  end
265
300
  if kot_today_highlighted
266
301
  Kobot.logger.warn(
267
- "Today=#{@kot_today} is highlighted (holiday) but not marked as 休日"
302
+ "Today=#{@kot_data[:today]} is highlighted (holiday) but not marked as #{@selector.kot_workday_time_off_text}"
268
303
  )
269
304
  end
270
305
  kot_today_highlighted
@@ -276,8 +311,8 @@ module Kobot
276
311
  "<b>Date:</b> #{@today}",
277
312
  "<b>Status:</b> <span style='color:#{color}'>#{status}</span>"
278
313
  ]
279
- message << "<b>Clock_in:</b> #{@kot_today_clock_in}" if clock
280
- message << "<b>Clock_out:</b> #{@kot_today_clock_out}" if clock == :out
314
+ message << "<b>Clock_in:</b> #{@kot_data[:today_clock_in]}" if clock
315
+ message << "<b>Clock_out:</b> #{@kot_data[:today_clock_out]}" if clock == :out
281
316
  message.join('<br>')
282
317
  end
283
318
  end
@@ -1,12 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kobot
4
- class KotRecordError < StandardError
5
- end
6
-
7
- class KotClockInError < StandardError
8
- end
9
-
10
- class KotClockOutError < StandardError
11
- end
4
+ class KotRecordError < StandardError; end
5
+ class KotClockInError < StandardError; end
6
+ class KotClockOutError < StandardError; end
12
7
  end
data/lib/kobot/option.rb CHANGED
@@ -27,6 +27,13 @@ module Kobot
27
27
  options[:skip] = skip
28
28
  end
29
29
 
30
+ opt.on('-a', '--auto-skip-without [SCHEDULE]',
31
+ 'Enable automatic skipping by reading schedule from the Time Card page;',
32
+ 'skip today if the provided text is not contained in the schedule column',
33
+ 'on the Time Card page; by default 裁量労働 is used') do |schedule|
34
+ options[:auto_skip_without] = schedule
35
+ end
36
+
30
37
  opt.on('-t', '--to [TO]',
31
38
  'Email address to send notification to; by default it is sent to',
32
39
  'the same self email account used in SMTP config as the sender') do |to|
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kobot
4
+ # The texts used in selectors to identify the elements on KOT UI.
5
+ class Selector
6
+ attr_accessor :login_success_notification_text,
7
+ :location_area_notification_text,
8
+ :time_card_menu_link_text,
9
+ :kot_date_saturday,
10
+ :kot_date_sunday,
11
+ :kot_workday_time_off_text,
12
+ :logout_menu_link_text
13
+
14
+ class << self
15
+ def en
16
+ selector = Selector.new
17
+ selector.login_success_notification_text = 'Data has been obtained'
18
+ selector.location_area_notification_text = 'Obtained location'
19
+ selector.time_card_menu_link_text = 'Time Card'
20
+ selector.kot_date_saturday = 'Sat'
21
+ selector.kot_date_sunday = 'Sun'
22
+ selector.kot_workday_time_off_text = 'time-off'
23
+ selector.logout_menu_link_text = 'Sign out'
24
+ selector
25
+ end
26
+
27
+ def ja
28
+ selector = Selector.new
29
+ selector.login_success_notification_text = 'データを取得しました'
30
+ selector.location_area_notification_text = '位置情報取得済み'
31
+ selector.time_card_menu_link_text = 'タイムカード'
32
+ selector.kot_date_saturday = '土'
33
+ selector.kot_date_sunday = '日'
34
+ selector.kot_workday_time_off_text = '休日'
35
+ selector.logout_menu_link_text = 'ログアウト'
36
+ selector
37
+ end
38
+ end
39
+ end
40
+ end
data/lib/kobot/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kobot
4
- VERSION = '1.2.2'
4
+ VERSION = '1.3.0'
5
5
  end
data/lib/kobot.rb CHANGED
@@ -4,6 +4,7 @@ require 'kobot/version'
4
4
  require 'kobot/exception'
5
5
  require 'kobot/option'
6
6
  require 'kobot/config'
7
+ require 'kobot/selector'
7
8
  require 'kobot/credential'
8
9
  require 'kobot/logger'
9
10
  require 'kobot/mailer'
@@ -33,6 +34,7 @@ module Kobot
33
34
  config.dryrun = options[:dryrun]
34
35
  config.force = options[:force]
35
36
  config.skip = options[:skip] || []
37
+ config.auto_skip_without = options[:auto_skip_without] || '裁量労働'
36
38
 
37
39
  config.kot_url = 'https://s2.kingtime.jp/independent/recorder/personal/'
38
40
  config.kot_timezone_offset = '+09:00'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kobot
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.2
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Jiang
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-09-03 00:00:00.000000000 Z
11
+ date: 2021-12-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: webdrivers
@@ -83,6 +83,7 @@ files:
83
83
  - lib/kobot/logger.rb
84
84
  - lib/kobot/mailer.rb
85
85
  - lib/kobot/option.rb
86
+ - lib/kobot/selector.rb
86
87
  - lib/kobot/version.rb
87
88
  homepage: https://github.com/yuan-jiang/kobot
88
89
  licenses:
@@ -107,7 +108,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
107
108
  - !ruby/object:Gem::Version
108
109
  version: '0'
109
110
  requirements: []
110
- rubygems_version: 3.0.3
111
+ rubygems_version: 3.1.2
111
112
  signing_key:
112
113
  specification_version: 4
113
114
  summary: Kobot automates the clock in/out of KING OF TIME.