shunkuntype 1.1.0 → 1.1.2

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.
data/README.md CHANGED
@@ -25,22 +25,11 @@ Usage: shunkuntype [options]
25
25
  -v, --version show program Version.
26
26
  -c, --check Check speed
27
27
  -d, --drill [VAL] one minute Drill [VAL]
28
- -h, --history view training History
29
- -p, --plot Plot personal data
30
- -s, --submit Submit data to dmz0
31
- --review [VALUE] Review training, VALUE=html or hiki
28
+ -h, --help show help message
29
+ -l, --log view training Log
32
30
  ```
33
31
  For the first time, shunkun makes .shunkuntype directory on the home dir,
34
- and put three data files(training, speed, server).
35
- The training and speed data will be sent to the server, when --submit.
36
- The --review will get the data download, and show the training and speed data in hiki or html formats,
37
- where the png files created by gnuplot.
38
-
39
- For activating server all training member has ssh access, and the write permission on the directory.
40
- The format of the server_data.txt is as follows:
41
- ```
42
- [login_name]\@[server_name]:directory
43
- ```
32
+ and put two data files(training, speed).
44
33
 
45
34
  ## Development
46
35
 
@@ -6,37 +6,25 @@ require 'fileutils'
6
6
  module DataFiles
7
7
 
8
8
  def self.prepare
9
- data_path = File.join(ENV['HOME'], '.shunkuntype','training_data.txt')
9
+ speed_path = Shunkuntype::SPEED_FILE
10
+ training_path = Shunkuntype::TRAINING_FILE
10
11
 
11
- create_file_if_not_exists(data_path)
12
+ create_file_if_not_exists(speed_path)
13
+ create_file_if_not_exists(training_path)
12
14
  end
13
15
 
14
16
  def self.create_file_if_not_exists(path)
15
17
  create_file_path(path)
16
-
17
- return if File::exist?(path)
18
- create_data_files
18
+ unless File.exist?(path)
19
+ File.open(path, 'w') {} # 空ファイルを作成
20
+ puts "Created #{path}"
21
+ end
19
22
  end
20
23
 
21
24
  def self.create_file_path(path)
22
25
  FileUtils.mkdir_p File.dirname(path)
23
26
  end
24
27
 
25
- def self.create_data_files
26
- if File::exist?("./speed_data.txt") then
27
- system "mv ./speed_data.txt #{Shunkuntype::SPEED_FILE}"
28
- print "moving ./speed_data.txt #{Shunkuntype::SPEED_FILE}.\n"
29
- end
30
- if File::exist?("./training_data.txt") then
31
- system "mv ./training_data.txt #{Shunkuntype::TRAINING_FILE}"
32
- print "moving ./training_data.txt #{Shunkuntype::TRAINING_FILE}.\n"
33
- if File::exist?(Shunkuntype::TRAINING_FILE) then
34
- print "#{Shunkuntype::TRAINING_FILE} exits.\n"
35
- File::open(Shunkuntype::TRAINING_FILE,'a')
36
- print "make #{Shunkuntype::TRAINING_FILE}\n"
37
- end
38
- end
39
- end
40
- private_class_method :create_file_if_not_exists, :create_file_path, :create_data_files
28
+ private_class_method :create_file_if_not_exists, :create_file_path
41
29
  end
42
30
 
@@ -1,4 +1,5 @@
1
1
  require "shunkuntype"
2
+ require_relative "db" # 追加
2
3
 
3
4
  class SpeedCheck
4
5
  attr_reader :number, :period
@@ -22,17 +23,24 @@ class SpeedCheck
22
23
  end
23
24
 
24
25
  def check_data_files
26
+ retried = false
25
27
  begin
26
- file=open(Shunkuntype::SPEED_FILE,"r")
28
+ file = open(Shunkuntype::SPEED_FILE, "r")
27
29
  if file
28
30
  puts "#{Shunkuntype::SPEED_FILE} opened succcessfully"
29
31
  end
30
32
  rescue
31
- puts "#{Shunkuntype::SPEED_FILE} does not exist in this directory. --init or try in another dir."
32
- exit
33
+ if retried
34
+ puts "Failed to create #{Shunkuntype::SPEED_FILE}. Please check permissions."
35
+ exit 1
36
+ end
37
+ puts "#{Shunkuntype::SPEED_FILE} does not exist in this directory. Creating required files..."
38
+ DataFiles.prepare
39
+ retried = true
40
+ retry
33
41
  end
34
42
  end
35
-
43
+
36
44
  def mk_random_words
37
45
  data=[]
38
46
  data_dir=File.expand_path('../../../lib/data', __FILE__)
@@ -2,6 +2,6 @@ require 'fileutils'
2
2
  require 'tmpdir'
3
3
 
4
4
  module Shunkuntype
5
- VERSION = "1.1.0"
5
+ VERSION = "1.1.2"
6
6
  data_dir = File.join(ENV['HOME'], '.shunkuntype')
7
7
  end
data/lib/shunkuntype.rb CHANGED
@@ -24,7 +24,6 @@ end
24
24
  class Command
25
25
 
26
26
  def self.run(argv=[])
27
- print "Shunkuntype says 'Hello world'.\n"
28
27
  new(argv).execute
29
28
  end
30
29
 
@@ -35,7 +34,8 @@ class Command
35
34
  def execute
36
35
  DataFiles.prepare
37
36
 
38
- @argv << '--help' if @argv.size==0
37
+ @mode = nil
38
+
39
39
  command_parser = OptionParser.new do |opt|
40
40
  opt.on('-v', '--version','show program Version.') { |v|
41
41
  opt.version = Shunkuntype::VERSION
@@ -45,8 +45,103 @@ class Command
45
45
  opt.on('-d', '--drill [VAL]','one minute Drill [VAL]', Integer) {|v| Training.new(v) }
46
46
  opt.on('-h', '--help','show help message') { puts opt; exit }
47
47
  opt.on('-l','--log','view training log') {|v| FinishCheck.new }
48
+ opt.on('-r MODE', '--record MODE',
49
+ "Show record data in readable format.\n" \
50
+ " MODE can be:\n" \
51
+ " all Show both speed and training data (default)\n" \
52
+ " plot Output matplotlib code for plotting\n" \
53
+ " speed_data Show only speed data\n" \
54
+ " training_data Show only training data"
55
+ ) {|mode| @mode = mode }
56
+ # opt.on('-r', '--record', 'Show both speed and training data (same as -r all)') { @mode = 'all' }
48
57
  end
49
58
  command_parser.parse!(@argv)
59
+ # データ表示
60
+ case @mode
61
+ when 'plot', 'python'
62
+ print_python_plot_code
63
+ exit
64
+ when 'speed_data'
65
+ print_csv_pretty(Shunkuntype::SPEED_FILE, %w[Time Words TimeSec Score])
66
+ exit
67
+ when 'training_data'
68
+ print_csv_pretty(Shunkuntype::TRAINING_FILE, %w[Time Words TimeSec Score])
69
+ exit
70
+ when 'all'
71
+ print_pretty_data
72
+ exit
73
+ end
74
+
75
+ @argv << '--help' if @argv.size==0
76
+ command_parser.parse!(@argv)
50
77
  exit
51
78
  end
79
+
80
+ private
81
+
82
+ def print_pretty_data
83
+ print_csv_pretty(Shunkuntype::SPEED_FILE, %w[Time Words TimeSec Score])
84
+ print_csv_pretty(Shunkuntype::TRAINING_FILE, %w[Time Words TimeSec Score])
85
+ end
86
+
87
+ def print_csv_pretty(path, headers)
88
+ if File.exist?(path)
89
+ puts "== #{File.basename(path)} =="
90
+ puts headers.join("\t")
91
+ File.foreach(path) do |line|
92
+ puts line.chomp.split(',').join("\t")
93
+ end
94
+ puts
95
+ else
96
+ puts "#{path} not found."
97
+ end
98
+ end
99
+
100
+ def print_python_plot_code
101
+ speed_path = Shunkuntype::SPEED_FILE
102
+ training_path = Shunkuntype::TRAINING_FILE
103
+ puts "# Python (matplotlib) code for plotting your typing data"
104
+ puts "# Save this as plot_typing.py and run: python plot_typing.py"
105
+ puts <<~PYTHON
106
+ import matplotlib.pyplot as plt
107
+ import csv
108
+ from datetime import datetime
109
+
110
+ def load_data(path):
111
+ times, scores = [], []
112
+ try:
113
+ with open(path) as f:
114
+ reader = csv.reader(f)
115
+ for row in reader:
116
+ if len(row) < 4:
117
+ continue
118
+ # row[0]: time, row[2]: score
119
+ try:
120
+ t = datetime.strptime(row[0].split('.')[0], '%Y-%m-%d %H:%M:%S %z')
121
+ s = float(row[2])
122
+ times.append(t)
123
+ scores.append(s)
124
+ except Exception:
125
+ continue
126
+ except FileNotFoundError:
127
+ pass
128
+ return times, scores
129
+
130
+ speed_times, speed_scores = load_data("#{speed_path}")
131
+ train_times, train_scores = load_data("#{training_path}")
132
+
133
+ plt.figure(figsize=(10,5))
134
+ if speed_times:
135
+ plt.plot(speed_times, speed_scores, 'o-', label='Speed')
136
+ if train_times:
137
+ plt.plot(train_times, train_scores, 's-', label='Training')
138
+ plt.xlabel('Date')
139
+ plt.ylabel('Score')
140
+ plt.title('Typing Progress')
141
+ plt.legend()
142
+ plt.grid(True)
143
+ plt.tight_layout()
144
+ plt.show()
145
+ PYTHON
146
+ end
52
147
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shunkuntype
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shigeto R. Nishitani
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2025-11-15 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: systemu
@@ -122,6 +121,8 @@ files:
122
121
  - ".hyper_card/docs/shunkun_report.pdf"
123
122
  - ".hyper_card/docs/speed.png"
124
123
  - ".hyper_card/docs/work.png"
124
+ - ".hyper_card/history/plot_modes.md"
125
+ - ".hyper_card/history/plot_modes_251118.md"
125
126
  - ".hyper_card/history/test_cli_bdd.md"
126
127
  - ".hyper_card/history/test_cli_bdd_251114.md"
127
128
  - ".hyper_card/history/tidy.md"
@@ -244,13 +245,10 @@ files:
244
245
  - lib/shunkuntype/training.rb
245
246
  - lib/shunkuntype/version.rb
246
247
  - shunkuntype.gemspec
247
- - shunkuntype/speed_data.txt
248
- - shunkuntype/training_data.txt
249
248
  homepage: https://github.com/daddygongon/shunkuntype
250
249
  licenses:
251
250
  - MIT
252
251
  metadata: {}
253
- post_install_message:
254
252
  rdoc_options: []
255
253
  require_paths:
256
254
  - lib
@@ -265,8 +263,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
265
263
  - !ruby/object:Gem::Version
266
264
  version: '0'
267
265
  requirements: []
268
- rubygems_version: 3.4.19
269
- signing_key:
266
+ rubygems_version: 3.6.7
270
267
  specification_version: 4
271
268
  summary: type training.
272
269
  test_files: []
@@ -1,6 +0,0 @@
1
- 2024-11-06 21:13:42 +0900,20,39.937564,184.7884362701741
2
- 2025-09-09 17:30:33 +0900,20,37.889581,177.35746404796612
3
- 2025-09-09 17:35:35 +0900,20,37.433635,160.28365933471326
4
- 2025-11-14 11:37:14 +0900,20,46.516022,145.75622997168588
5
- 2025-11-14 15:43:37 +0900,20,39.598636,165.1572038996495
6
- 2025-11-14 16:08:21 +0900,20,37.490195,166.4435194322142
@@ -1,36 +0,0 @@
1
- 2021-04-06 14:41:09 +0900,STEP-1.txt,28,60
2
- 2021-04-06 14:42:24 +0900,STEP-2.txt,46,60
3
- 2021-04-06 14:44:15 +0900,STEP-91.txt,28,60
4
- 2021-06-02 17:42:48 +0900,STEP-1.txt,55,60
5
- 2021-07-08 11:59:48 +0900,STEP-3.txt,23,60
6
- 2021-07-08 12:01:20 +0900,STEP-36.txt,16,60
7
- 2021-07-08 12:02:53 +0900,STEP-9.txt,15,60
8
- 2022-03-08 15:16:08 +0900,STEP-1.txt,57,60
9
- 2022-03-08 15:18:41 +0900,STEP-5.txt,38,60
10
- 2022-03-08 15:20:14 +0900,STEP-7.txt,48,60
11
- 2022-03-08 15:22:06 +0900,STEP-4.txt,1,60
12
- 2022-03-08 15:23:58 +0900,STEP-4.txt,44,60
13
- 2022-03-09 13:14:02 +0900,STEP-8.txt,35,60
14
- 2022-04-14 14:40:28 +0900,STEP-3.txt,12,60
15
- 2022-04-14 14:42:18 +0900,STEP-4.txt,40,60
16
- 2022-04-18 14:00:48 +0900,STEP-1.txt,4,60
17
- 2022-04-18 14:04:04 +0900,STEP-46.txt,47,60
18
- 2022-04-20 16:38:30 +0900,STEP-1.txt,50,60
19
- 2022-04-20 16:40:17 +0900,STEP-2.txt,51,60
20
- 2022-06-02 13:09:59 +0900,STEP-2.txt,15,60
21
- 2023-05-25 17:24:23 +0900,STEP-6.txt,50,60
22
- 2023-05-25 17:25:40 +0900,STEP-10.txt,55,60
23
- 2023-05-25 17:26:47 +0900,STEP-11.txt,39,60
24
- 2023-05-25 17:27:59 +0900,STEP-12.txt,44,60
25
- 2023-07-27 11:36:42 +0900,STEP-15.txt,36,60
26
- 2024-04-24 11:36:58 +0900,STEP-1.txt,60,60
27
- 2024-04-24 11:39:15 +0900,STEP-20.txt,48,60
28
- 2024-08-22 11:57:27 +0900,STEP-51.txt,46,60
29
- 2025-02-05 12:22:37 +0900,STEP-15.txt,42,60
30
- 2025-11-14 11:35:56 +0900,STEP-16.txt,44,60
31
- 2025-11-14 15:28:03 +0900,STEP-1.txt,0,60
32
- 2025-11-14 15:31:52 +0900,STEP-1.txt,0,60
33
- 2025-11-14 15:32:49 +0900,STEP-1.txt,0,60
34
- 2025-11-14 15:39:20 +0900,STEP-1.txt,0,60
35
- 2025-11-14 15:40:03 +0900,STEP-1.txt,0,60
36
- 2025-11-14 15:53:27 +0900,STEP-1.txt,0,60