morsby 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4ec402a96e99a1dd7a5bcf671343df1ef2cf896ac3a66e4fc0ec637f55e4c32a
4
+ data.tar.gz: '096b0719f4e3dc9359a1531fe59f6880e093f9db24697f7ece6066ff89c7ac93'
5
+ SHA512:
6
+ metadata.gz: 8131fba53901c1b848201d5bed070542a931c32b57bd21712b6826f7eaed5c4673b175428b06ec71fe55701c438ca4e7c971cbe27656468aea15ad3db4c4ba70
7
+ data.tar.gz: 5085ce030f6b0aeae4c6aab3a4c39d16c4ed8a56dac85f0c1ecd98e7ba4335191852d9af5c9d420c3d2097067834c43911393737b9cd205b531cdf410000b5a6
data/CHANGELOG.md ADDED
@@ -0,0 +1,23 @@
1
+ # CHANGELOG
2
+
3
+ ## 0.1.0
4
+ ---
5
+ **初回リリース (First Release)**
6
+
7
+ モールス信号の基礎から、アルファベット・数字・記号・Q符号・CW略語・和文モールスまで対応し、
8
+ 学習モード(対話型)と出力モードを実装しました。
9
+
10
+ - `morsby -h`でヘルプ表示
11
+ - `morsby -learn`で学習モードに入り、基礎知識や略語一覧、クイズを通じて練習可能
12
+ - `morsby "HELLO"`で文字列をモールス信号へ変換して出力
13
+ - `--lang en`で英語表示、`--pro`で高速なプロモード対応
14
+ - 和文、濁音・半濁音、記号(?)にも対応
15
+
16
+ This initial release introduces a comprehensive Morse code tool supporting alphabets (A-Z), digits (0-9), punctuation (?), Q-codes, CW abbreviations, and Wabun Morse.
17
+ It offers both an interactive learning mode and a direct output mode.
18
+
19
+ - Show help `morsby -h`
20
+ - Enter learning mode with `morsby -learn` to study basics, Q-codes, CW abbreviations, and practice quizzes
21
+ - Convert a given string to Morse code with `morsby "HELLO"`
22
+ - `--lang en` for English interface, `--pro` for faster (professional) mode
23
+ - Also supports Japanese Wabun Morse, including voiced and semi-voiced characters, as well as punctuation like `?`
data/README.md ADDED
@@ -0,0 +1,91 @@
1
+ # README
2
+
3
+ ## Overview
4
+
5
+ Morsbyは、モールス信号の学習・活用を支援するツールです。
6
+ 英字(A-Z)、数字(0-9)、記号(?)、Q符号、CW略語、和文モールスまで対応。
7
+
8
+ 学習モードで基礎を固めたり、クイズで理解度を確認したり、文字列を即座にモールス信号へ変換したりできます。
9
+ また、英語表示(`--lang en`)やプロモード(`--pro`)による高速再生にも対応します。
10
+
11
+ ※筆者の勉強用でもあり、内容についての正確性は保証致しません。
12
+ ※雑なコード/機能が多々ありますのでIssueやPR発行いただければ嬉しいです。
13
+
14
+ Morsby is a tool to learn and utilize Morse code.
15
+ It supports alphabets (A-Z), digits (0-9), punctuation (?), Q-codes, CW abbreviations, and Japanese Wabun Morse.
16
+ Use the learning mode to practice basics and test your skills with quizzes, or instantly convert input strings to Morse code.
17
+ Features an English mode (`--lang en`) and a pro mode (`--pro`) for faster playback.
18
+
19
+ Note: This content is also for the author’s own study, and its accuracy is not guaranteed.
20
+ Note: There may be rough or imperfect code/functions in places, so issues and pull requests are welcome.
21
+
22
+ ## Install
23
+
24
+ install morsby
25
+
26
+ ```
27
+ gem install morsby
28
+ ```
29
+
30
+ install sox for playing morse sound
31
+
32
+ ### For Mac
33
+
34
+ ```
35
+ brew install sox
36
+ ```
37
+
38
+ ### For Linux(CentOS)
39
+
40
+ ```
41
+ sudo yum install sox
42
+ ```
43
+
44
+ ### For Linux(Debian/Ubuntu)
45
+
46
+ ```
47
+ sudo apt-get install sox
48
+ ```
49
+
50
+ This tool does not support Windows yet.
51
+
52
+ ## Usage
53
+
54
+ ### Learning Mode
55
+
56
+ ```
57
+ morsby -learn
58
+ ```
59
+
60
+ Main menu: basics, Q-codes, CW abbreviations, quizzes.
61
+
62
+ ### Output Mode
63
+
64
+ ```
65
+ morsby "HELLO"
66
+ ```
67
+
68
+ Converts HELLO into Morse code.
69
+
70
+ ### オプション (Options)
71
+
72
+ `--lang en`: English
73
+ `--pro`: High speed mode
74
+
75
+ ### Example
76
+
77
+ ```
78
+ morsby "Rubyist"
79
+ morsby --pro "HELLO RUBYIST"
80
+ morsby -learn
81
+ morsby -learn --lang en
82
+ morsby -learn --pro
83
+ morsby -learn --pro --lang en
84
+ ```
85
+
86
+ ## Development & Test
87
+
88
+ ```
89
+ bundle install
90
+ bundle exec rspec
91
+ ```
data/bin/morsby ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "morsby"
5
+
6
+ Morsby::CLI.new.run(ARGV)
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Morsby
4
+ ABBREVIATIONS = {
5
+ essential: [
6
+ { name: "CQ", ja: "一般呼出", en: "General call" },
7
+ { name: "DE", ja: "こちらは", en: "From (this station)" },
8
+ { name: "K", ja: "どうぞ送れ", en: "Over, go ahead" },
9
+ { name: "R", ja: "了解", en: "Roger, received" },
10
+ { name: "AR", ja: "メッセージ終了", en: "End of message" },
11
+ { name: "AS", ja: "待て", en: "Wait" },
12
+ { name: "BT", ja: "区切り", en: "Break between sections" },
13
+ { name: "SK", ja: "通信終了", en: "End of contact" },
14
+ { name: "SOS",ja: "遭難信号", en: "Distress signal" },
15
+ { name: "TNX",ja: "感謝", en: "Thanks" }
16
+ ],
17
+
18
+ q_signs: [
19
+ { name: "QRM", ja: "他局混信", en: "Interference" },
20
+ { name: "QRN", ja: "雑音有", en: "Atmospheric noise" },
21
+ { name: "QRP", ja: "出力下げ", en: "Reduce power" },
22
+ { name: "QRT", ja: "送信停止", en: "Stop transmitting" },
23
+ { name: "QRV", ja: "準備OK?", en: "Ready?" },
24
+ { name: "QRX", ja: "後で呼ぶ", en: "Call later" },
25
+ { name: "QSB", ja: "信号変動", en: "Signals fading" },
26
+ { name: "QSL", ja: "受領了解", en: "Acknowledgement" },
27
+ { name: "QSO", ja: "交信中", en: "A contact" },
28
+ { name: "QSY", ja: "周波数変更", en: "Change frequency" }
29
+ ],
30
+
31
+ cw_signs: [
32
+ { name: "OM", ja: "男性オペレーターに親しみを込めて呼ぶ呼称", en: "Male operator (OM)" },
33
+ { name: "YL", ja: "女性オペレーターに親しみを込めて呼ぶ呼称", en: "Lady operator (YL)" },
34
+ { name: "XYL", ja: "妻", en: "Wife (XYL)" },
35
+ { name: "FB", ja: "良好", en: "Fine Business" },
36
+ { name: "GM", ja: "おはよう", en: "Good Morning" },
37
+ { name: "GN", ja: "おやすみ", en: "Good Night" },
38
+ { name: "GA", ja: "こんにちは(午後)", en: "Good Afternoon" },
39
+ { name: "GE", ja: "こんばんは", en: "Good Evening" },
40
+ { name: "CU", ja: "また会おう", en: "See you" },
41
+ { name: "CUL", ja: "また会いましょう", en: "See you later" },
42
+ { name: "PSE", ja: "お願いします", en: "Please" }
43
+ ]
44
+ }.freeze
45
+ end
data/lib/morsby/cli.rb ADDED
@@ -0,0 +1,337 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'version'
4
+ require_relative 'morse_table'
5
+ require_relative 'wabun_table'
6
+ require_relative 'abbreviations'
7
+ require_relative 'messages'
8
+ require 'nkf'
9
+
10
+ module Morsby
11
+ class CLI
12
+ PUNCTUATION_CODES = {
13
+ '?' => '..--..',
14
+ '.' => '.-.-.-',
15
+ ',' => '--..--',
16
+ '/' => '-..-.',
17
+ '-' => '-....-',
18
+ '(' => '-.--.',
19
+ ')' => '-.--.-'
20
+ }
21
+
22
+ # デフォルト(ビギナーモード)とプロモードの音長
23
+ DEFAULT_DOT_UNIT = 0.15
24
+ PRO_DOT_UNIT = 0.08
25
+
26
+ # モールス仕様:
27
+ # 短音=1拍、長音=3拍、文字内パーツ間=1拍、文字間=3拍、単語間=7拍
28
+ # だが、文字間は3だと短く感じたので4に修正した
29
+ # 単語間はスペースで分割し、その際7拍分空ける
30
+
31
+ def run(argv)
32
+ @language = :ja
33
+ if (lang_index = argv.index("--lang")) || (lang_index = argv.index("-lang"))
34
+ desired_lang = argv[lang_index + 1]
35
+ @language = :en if desired_lang && desired_lang.downcase == "en"
36
+ argv.delete_at(lang_index + 1)
37
+ argv.delete_at(lang_index)
38
+ end
39
+
40
+ # プロモード判定
41
+ @dot_unit = DEFAULT_DOT_UNIT
42
+ if (pro_index = argv.index("--pro"))
43
+ @dot_unit = PRO_DOT_UNIT
44
+ argv.delete_at(pro_index)
45
+ end
46
+
47
+ @dash_unit = @dot_unit * 3
48
+ @intra_char_gap = @dot_unit
49
+ @letter_gap = @dot_unit * 3
50
+ @word_gap = @dot_unit * 7
51
+
52
+ if argv.empty?
53
+ print_help
54
+ return
55
+ end
56
+
57
+ input_str = argv.join(" ")
58
+ if input_str.start_with?("-h") || input_str.start_with?("-help")
59
+ print_help
60
+ return
61
+ elsif input_str.start_with?("-learn")
62
+ @mode = :learn
63
+ learn_mode_interactive
64
+ else
65
+ @mode = :output
66
+ unless play_installed? && !on_windows?
67
+ show_audio_error_message
68
+ return
69
+ end
70
+ convert_and_sound(input_str)
71
+ end
72
+ end
73
+
74
+ private
75
+
76
+ def msg(key)
77
+ val = Morsby::MESSAGES[@language][key]
78
+ val.is_a?(Proc) ? val : val
79
+ end
80
+
81
+ def print_help
82
+ puts msg(:help)
83
+ end
84
+
85
+ def learn_mode_interactive
86
+ intro
87
+ loop do
88
+ print_main_menu
89
+ choice = STDIN.gets.strip
90
+ break if choice.downcase == 'q'
91
+
92
+ case choice
93
+ when "1"
94
+ show_basic_course
95
+ when "2"
96
+ show_q_cw_detail_course
97
+ when "3"
98
+ show_alphabets
99
+ when "4"
100
+ learn_all_digits
101
+ when "5"
102
+ show_punctuation
103
+ when "6"
104
+ show_wabun_course
105
+ when "7"
106
+ learn_abbrev(:essential, :abbrev_essential_title)
107
+ when "8"
108
+ learn_abbrev(:q_signs, :abbrev_q_signs_title)
109
+ when "9"
110
+ learn_abbrev(:cw_signs, :abbrev_cw_signs_title)
111
+ when "10"
112
+ quiz_characters
113
+ when "11"
114
+ quiz_sound
115
+ else
116
+ puts (@language == :ja ? "無効な選択です。もう一度お試しください。" : "Invalid choice. Please try again.")
117
+ end
118
+ end
119
+ puts msg(:learning_mode_end)
120
+ end
121
+
122
+ def intro
123
+ puts "=== Morse Code Learning Mode ==="
124
+ puts msg(:learning_intro)
125
+ puts
126
+ puts msg(:press_enter_main)
127
+ STDIN.gets
128
+ end
129
+
130
+ def print_main_menu
131
+ puts msg(:main_menu)
132
+ end
133
+
134
+ def show_basic_course
135
+ puts msg(:about_morse)
136
+ STDIN.gets
137
+ end
138
+
139
+ def show_q_cw_detail_course
140
+ puts msg(:q_cw_detail_course)
141
+ STDIN.gets
142
+ end
143
+
144
+ def show_alphabets
145
+ puts msg(:all_alphabets_title)
146
+ ('A'..'Z').each do |char|
147
+ code = Morsby::MORSE_TABLE[char]
148
+ puts "#{char}: #{code}"
149
+ end
150
+ puts msg(:press_enter_return)
151
+ STDIN.gets
152
+ end
153
+
154
+ def learn_all_digits
155
+ puts msg(:all_digits)
156
+ ('0'..'9').each do |d|
157
+ puts "#{d}: #{Morsby::MORSE_TABLE[d]}"
158
+ end
159
+ puts msg(:press_enter_return)
160
+ STDIN.gets
161
+ end
162
+
163
+ def show_punctuation
164
+ puts msg(:symbol_title)
165
+ PUNCTUATION_CODES.each do |sym, code|
166
+ puts "#{sym}: #{code}"
167
+ end
168
+ puts msg(:press_enter_return)
169
+ STDIN.gets
170
+ end
171
+
172
+ def show_wabun_course
173
+ puts msg(:wabun_title)
174
+ Morsby::WABUN_TABLE.each do |kana, code|
175
+ puts "#{kana}: #{code}"
176
+ end
177
+ puts
178
+ if @language == :ja
179
+ puts "濁音・半濁音もテーブルに直接定義済み。例: ガ、パなど"
180
+ else
181
+ puts "Dakuon and Handakuon are directly defined in the WABUN_TABLE."
182
+ end
183
+ puts msg(:press_enter_return)
184
+ STDIN.gets
185
+ end
186
+
187
+ def learn_abbrev(type, title_key)
188
+ puts msg(title_key)
189
+ Morsby::ABBREVIATIONS[type].each do |abbrev|
190
+ code = abbrev[:name].chars.map { |c| Morsby::MORSE_TABLE[c] }.compact.join(" ")
191
+ meaning_ja = abbrev[:ja]
192
+ meaning_en = abbrev[:en]
193
+ puts format(msg(:abbrev_format), name: abbrev[:name], morse_code: code, meaning_ja: meaning_ja, meaning_en: meaning_en)
194
+ puts
195
+ end
196
+ puts msg(:press_enter_return)
197
+ STDIN.gets
198
+ end
199
+
200
+ def quiz_characters
201
+ puts msg(:quiz_char_start)
202
+ all_chars = Morsby::MORSE_TABLE.keys
203
+ correct_count = 0
204
+ 10.times do |i|
205
+ question = all_chars.sample
206
+ code = Morsby::MORSE_TABLE[question]
207
+ puts msg(:quiz_char_question).call(i)
208
+ puts "Morse: #{code}"
209
+ print (@language == :ja ? "文字は?: " : "Character?: ")
210
+ answer = STDIN.gets.strip.upcase
211
+ if answer == question
212
+ puts msg(:quiz_correct)
213
+ correct_count += 1
214
+ else
215
+ puts msg(:quiz_incorrect).call(question)
216
+ end
217
+ puts
218
+ end
219
+ puts msg(:quiz_result).call(correct_count)
220
+ STDIN.gets
221
+ end
222
+
223
+ def quiz_sound
224
+ unless play_installed? && !on_windows?
225
+ show_audio_error_message
226
+ return
227
+ end
228
+
229
+ puts msg(:quiz_sound_start)
230
+ all_chars = Morsby::MORSE_TABLE.keys
231
+ correct_count = 0
232
+ 10.times do |i|
233
+ question = all_chars.sample
234
+ code = Morsby::MORSE_TABLE[question]
235
+ puts msg(:quiz_sound_question).call(i)
236
+ code.chars.each_with_index do |c, idx|
237
+ play_signal(sig:c)
238
+ # 同一文字内パーツ間=短音1単位
239
+ sleep(@dot_unit) if idx < code.size-1
240
+ end
241
+ # 文字間=3単位
242
+ sleep(@dot_unit*3)
243
+ print "> "
244
+ answer = STDIN.gets.strip.upcase
245
+ if answer == question
246
+ puts msg(:quiz_correct)
247
+ correct_count += 1
248
+ else
249
+ puts msg(:quiz_incorrect).call(question)
250
+ end
251
+ puts
252
+ end
253
+ puts msg(:quiz_result).call(correct_count)
254
+ STDIN.gets
255
+ end
256
+
257
+ def play_installed?
258
+ system("which play > /dev/null 2>&1")
259
+ end
260
+
261
+ def on_windows?
262
+ RUBY_PLATFORM.downcase.include?('mswin') || RUBY_PLATFORM.downcase.include?('mingw')
263
+ end
264
+
265
+ def short_beep
266
+ # 短音=1単位
267
+ system("play -n synth #{@dot_unit} sine 700 > /dev/null 2>&1")
268
+ end
269
+
270
+ def long_beep
271
+ # 長音=3単位
272
+ system("play -n synth #{@dot_unit*3} sine 700 > /dev/null 2>&1")
273
+ end
274
+
275
+ def play_signal(sig:, show: false)
276
+ if sig == '.'
277
+ short_beep
278
+ print "." if show
279
+ else
280
+ long_beep
281
+ print "-" if show
282
+ end
283
+ end
284
+
285
+ def convert_and_sound(str)
286
+ normalized = NKF.nkf('-w -h0 -Z4 --katakana', str)
287
+
288
+ words = normalized.split(' ')
289
+
290
+ words.each_with_index do |word, w_idx|
291
+ chars = word.chars
292
+ chars.each_with_index do |ch, c_idx|
293
+ code = morse_for_char(ch)
294
+ next unless code
295
+ code.chars.each_with_index do |c, i|
296
+ play_signal(sig: c, show: true)
297
+ # 同一文字内パーツ間=1拍
298
+ sleep(@dot_unit)
299
+ end
300
+ # 文字間=4拍 (3ではなく4にしている)
301
+ sleep(@dot_unit*4)
302
+ print " "
303
+ end
304
+ # 単語間=7拍
305
+ sleep(@dot_unit*7)
306
+ print " "
307
+ end
308
+ end
309
+
310
+ def morse_for_char(ch)
311
+ upch = ch.upcase
312
+ if PUNCTUATION_CODES[upch]
313
+ return PUNCTUATION_CODES[upch]
314
+ end
315
+
316
+ if Morsby::MORSE_TABLE[upch]
317
+ return Morsby::MORSE_TABLE[upch]
318
+ end
319
+
320
+ code = Morsby::WABUN_TABLE[ch]
321
+ return code if code
322
+
323
+ nil
324
+ end
325
+
326
+ def show_audio_error_message
327
+ if @language == :ja
328
+ puts "\n音声を再生するには`sox`をインストールしてください。\n"
329
+ puts "また、現在Windowsにはまだ対応しておりません。\n"
330
+ puts "ラーニングモードは起動できます!" if @mode == :output
331
+ else
332
+ puts "\nPlease install 'sox' for sound. Currently not supported on Windows.\n"
333
+ puts "Learning mode is still available!!"
334
+ end
335
+ end
336
+ end
337
+ end
@@ -0,0 +1,211 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Morsby
4
+ MESSAGES = {
5
+ ja: {
6
+ help: <<~HELP,
7
+
8
+ 使用方法:
9
+ -----------------------------------------------------------------
10
+ morsby -h / -help : ヘルプ表示
11
+ morsby -learn : 学習モード(対話)
12
+ morsby "char" : 入力文字列をモールス信号で出力
13
+
14
+ オプション:
15
+ --lang en (英語モード。指定しない場合日本語モード。)
16
+ --pro (高速再生モード)
17
+ -----------------------------------------------------------------
18
+
19
+ HELP
20
+ learning_mode_end: "\n学習モードを終了します。",
21
+ learning_intro: "モールス信号は、短点と長点を組み合わせて文字・数字・記号を表す国際的な通信手段です。\n" \
22
+ "かつて、まだ電話やインターネットが普及する前、電報(電気信号による文字送信)が主な長距離通信手段だった時代から利用されてきました。\n" \
23
+ "この歴史的背景を持つモールス信号は、現在でも非常用や低帯域環境下で有効で、言語の壁を越えた情報伝達を可能にします。",
24
+ about_morse: "[1) モールス信号の基礎]\n" \
25
+ "モールス信号の基礎とは、短い信号(短点)と長い信号(長点)の組み合わせで文字や数字、記号を表現する仕組みを深く理解することにあります。\n" \
26
+ "A〜Zのアルファベットや0〜9の数字は、それぞれ固有のパターンを持ち、例えば“A”は「.−」、" \
27
+ "“B”は「−...」といった具合です。最初は符号表を参照しながら確認しますが、徐々に暗記し、聴いただけで文字が浮かぶようになります。\n\n" \
28
+ "また、記号(句読点や疑問符、スラッシュなど)もモールス信号で表せるため、単なる文字通信を超え、" \
29
+ "ある程度複雑なメッセージを送受できるようになります。これにより、長い文を高速に打電する必要はなく、" \
30
+ "短点と長点の組み合わせで十分な情報量を伝えることが可能です。\n\n" \
31
+ "モールス信号の特徴は、電力や設備が最小限で済む点にもあります。" \
32
+ "シンプルなトランシーバーや発信器、受信器があれば運用でき、" \
33
+ "電波状況が悪くても強弱ある信号を判別しやすく、極限的な環境でも通信が成立しやすいのです。" \
34
+ "また、音で伝えるだけでなく、光の点滅や振動など、視覚・触覚的な手段で伝達することも可能で、" \
35
+ "多様な場面で利用できます。\n\n" \
36
+ "学習の初期段階では、符号表を手元に置き、" \
37
+ "特定の文字のパターンを声に出したり、リズムで覚えたりする方法が有効です。" \
38
+ "慣れると、符号を見た瞬間に文字が浮かび、" \
39
+ "やがては音(ピッ・ピー)を聞くだけで瞬時に理解できるようになります。" \
40
+ "この過程は、まるで新しい言語を学ぶような感覚を伴い、" \
41
+ "習得によって得られる達成感も大きいものです。\n\n" \
42
+ "さらに、モールス信号は歴史的、文化的意義も持ち、" \
43
+ "かつては世界中で電報を送り合うための共通基盤でした。" \
44
+ "現代ではデジタル通信が主流ですが、モールスは緊急用のバックアップや、" \
45
+ "アマチュア無線でのチャレンジ精神、技術的スキルの証明手段として尊ばれています。" \
46
+ "これらの背景を知ることで、単なる通信手段としてだけでなく、" \
47
+ "モールス信号習得は世界的なコミュニティへの参加や歴史への接点ともなり得ます。\n\n" \
48
+ "こうした基礎を固めることで、必要最低限の符号で" \
49
+ "多様なメッセージを正確・迅速に伝える術を身につけることができ、" \
50
+ "非常用通信や特殊条件下での通信確保、国際的な趣味仲間との交流など、" \
51
+ "幅広い場面でその力が発揮できるようになります。",
52
+ press_enter_main: "Enterキーでメインメニューへ進んでください。",
53
+ main_menu: <<~MENU,
54
+
55
+ === メインメニュー ===
56
+ 1) モールス信号の基礎
57
+ 2) Q符号・CW符号とは
58
+ 3) アルファベット一覧 (A〜Z)
59
+ 4) 数字一覧 (0〜9)
60
+ 5) 記号一覧(?など)
61
+ 6) 和文一覧(ア〜ン、濁音・半濁音)
62
+ 7) これだけは覚えておきたいCW符号(10語)
63
+ 8) Q符号 一部紹介(Qコード)
64
+ 9) CW符号 一部紹介(一般的略号)
65
+ 10) ランダムクイズ(文字)
66
+ 11) ランダムクイズ(音声)
67
+ q) 終了
68
+ 選択(1-11, q):
69
+ MENU
70
+ q_cw_detail_course: <<~NODTL,
71
+
72
+ Q符号は、無線通信を円滑に行うために国際的に標準化された三文字の略号群で、すべて“Q”から始まります。
73
+ 例えば、QRMは他局の混信があることを示し、QRNは大気雑音の存在、QRPは送信出力を下げるよう要請する符号です。
74
+ これらQ符号を用いることで、詳細な文脈や長い文章なしに、短く明確な意図を伝達できます。
75
+ 言語や文化が異なるオペレーター間でも、Q符号を共有していれば、共通の“通信言語”として機能し、瞬時に状況を理解し合えるのです。
76
+
77
+ 一方、CW略号はアマチュア無線や国際通信で慣用的に用いられる短縮表現で、定型的な挨拶や状態報告を簡潔に行います。
78
+ たとえば、OMは男性オペレーターを親しみを込めて呼ぶ表現、YLは女性オペレーターを示す略称で、国籍や言語を超えて“仲間”として呼びかけやすくなります。
79
+ FBは“Fine Business”の略で“とても良い”という肯定的評価を素早く伝え、TNXは“Thanks”を短くして感謝を即座に示せます。
80
+ これらの略語を活用すれば、長いフレーズを何度も打つ必要がなくなり、交信時間を短縮して効率的なコミュニケーションを可能にします。
81
+
82
+ Q符号とCW略号を併せて使うことで、単なる符号の受け渡しを超え、互いの意図や状況を短時間で的確に伝え合えるようになります。
83
+ 電波状況が悪い、使用言語が異なる、緊急性が高いなど、多様な条件下でも、これらの略号は共通の合図として機能します。
84
+ その結果、オペレーター同士は必要最小限の符号で的確な応答が可能になり、国際的なネットワーク形成や相互理解を促進します。
85
+
86
+ Q符号はよりシステマティックな質問・指令的要素を担い、CW略号はより人間味や友好度を高める柔らかいコミュニケーション手段と言えます。
87
+ 両者を習熟すれば、無線通信における多言語・多文化の壁を薄め、効率性と親密さを両立させた、国際的で実用的な交信が実現します。
88
+
89
+ Enterキーでメインメニューへ戻ります。
90
+ NODTL
91
+ all_alphabets_title: "=== アルファベット一覧 (A〜Z) ===",
92
+ all_digits: "=== 数字一覧 (0〜9) ===",
93
+ symbol_title: "=== 記号一覧(?など) ===",
94
+ wabun_title: "=== 和文一覧(ア〜ン、濁音・半濁音) ===",
95
+ abbrev_essential_title: "=== これだけは覚えておきたいCW符号(10語) ===",
96
+ abbrev_q_signs_title: "=== Q符号 一部紹介(Qコード) ===",
97
+ abbrev_cw_signs_title: "=== CW符号 一部紹介(一般的略号) ===",
98
+ abbrev_format: "%<name>s: %<morse_code>s\n 日本語: %<meaning_ja>s\n English: %<meaning_en>s",
99
+ quiz_char_start: <<~QSTART,
100
+
101
+ === ランダムクイズ(文字) ===
102
+ A-Z,0-9から10問出題します。
103
+ モールス符号を表示するので、対応する文字を答えてください。
104
+ QSTART
105
+ quiz_sound_start: <<~QSTART,
106
+
107
+ === ランダムクイズ(音声) ===
108
+ A-Z,0-9から10問出題します。
109
+ 音で提示する符号から文字を判別してください。
110
+ QSTART
111
+ quiz_char_question: ->(i){ "問題#{i+1}: このモールス符号は何の文字?" },
112
+ quiz_sound_question: ->(i){ "問題#{i+1}: 音声再生。何の文字?" },
113
+ quiz_correct: "正解です!",
114
+ quiz_incorrect: ->(answer){ "惜しい!正解は #{answer} でした。" },
115
+ quiz_result: ->(count){ "クイズ終了! #{count}/10問正解。\nEnterキーでメインメニューに戻ります。" },
116
+ press_enter_return: "Enterキーでメインメニューに戻ります。"
117
+ },
118
+ en: {
119
+ help: <<~HELP,
120
+
121
+ Usage:
122
+ -----------------------------------------------------------------
123
+ morsby -h / -help : Show help
124
+ morsby -learn : Enter learning mode
125
+ morsby "char" : Convert input to Morse
126
+
127
+ Option:
128
+ --lang en (English mode. The Default is Japanese mode without this option.)
129
+ --pro (High speed mode)
130
+ -----------------------------------------------------------------
131
+
132
+ HELP
133
+ learning_mode_end: "\nExiting learning mode...",
134
+ learning_intro: "Morse code uses short and long signals to represent letters, digits, and symbols. " \
135
+ "It originated when telegraphs (sending text via electrical signals) were the primary long-distance communication method, long before telephones or the internet. " \
136
+ "This historical foundation makes Morse still valuable today in emergencies and low-bandwidth conditions, enabling meaningful exchange across language barriers.",
137
+ about_morse: "[1) Morse code basics]\n" \
138
+ "In Morse code basics, you learn how each letter (A-Z), digit (0-9), and punctuation mark corresponds to unique patterns of short and long signals. " \
139
+ "Initially, you consult a code chart, but with practice, you’ll recognize characters by sound alone. " \
140
+ "Morse’s low resource requirements make it reliable under poor conditions, and it can be conveyed via audio, light, or tactile means.\n\n" \
141
+ "This skill transforms simple tones into meaningful text, allowing seamless communication across language barriers and technical constraints. " \
142
+ "As you become proficient, the code feels like a new language—one where short/long tones become words in your mind without conscious translation. " \
143
+ "Historically central to telegraphy, Morse code still endures in amateur radio, emergency communications, and international friendships, " \
144
+ "offering a time-tested method to exchange information quickly and accurately.\n\n" \
145
+ "Mastering these basics empowers you to communicate in challenging scenarios, tap into a rich global tradition, and appreciate a technique " \
146
+ "that remains both practically valuable and culturally significant.",
147
+ press_enter_main: "Press Enter to proceed to the main menu.",
148
+ main_menu: <<~MENU,
149
+
150
+ === Main Menu ===
151
+ 1) Morse code basics
152
+ 2) About Q-codes & CW
153
+ 3) Alphabets (A-Z)
154
+ 4) Digits (0-9)
155
+ 5) Punctuation (?, ., etc.)
156
+ 6) Wabun (Japanese)
157
+ 7) Important abbreviations (10 words)
158
+ 8) Q-codes
159
+ 9) CW abbreviations
160
+ 10) Random Quiz (Characters)
161
+ 11) Random Quiz (Sound)
162
+ q) Quit
163
+ Select (1-11, q):
164
+ MENU
165
+ q_cw_detail_course: <<~NODTL,
166
+
167
+ Q-codes are internationally standardized three-letter codes (all starting with 'Q') designed to convey specific questions and instructions concisely.
168
+ For instance, QRM indicates interference from other stations, QRN signifies atmospheric noise, and QRP requests reduced transmitter power.
169
+ By using Q-codes, operators communicate critical information quickly and universally, without lengthy explanations or shared spoken language.
170
+ They serve as a common “lingua franca” in radio communication, allowing instant comprehension of operational conditions.
171
+
172
+ CW abbreviations, on the other hand, simplify common greetings and status reports into short forms.
173
+ For example, OM (for a male operator) and YL (for a female operator) enable friendly, direct addresses that transcend nationalities.
174
+ FB (Fine Business) quickly expresses approval or good conditions, and TNX (Thanks) efficiently conveys gratitude without typing full words.
175
+ Employing these abbreviations reduces message length, saves time, and creates a more personable, welcoming atmosphere during communication.
176
+
177
+ Together, Q-codes and CW abbreviations transform Morse exchanges into efficient and humanized interactions.
178
+ Regardless of language barriers, poor signal conditions, or urgency, these sets of shorthand ensure that essential meanings and camaraderie are conveyed promptly and accurately.
179
+ Mastering them empowers operators to forge international understanding, streamline their operations, and maintain a friendly rapport across borders.
180
+
181
+ Press Enter to return.
182
+ NODTL
183
+ all_alphabets_title: "=== Alphabets (A-Z) ===",
184
+ all_digits: "=== Digits (0-9) ===",
185
+ symbol_title: "=== Punctuation ===",
186
+ wabun_title: "=== Wabun (Japanese) ===",
187
+ abbrev_essential_title: "=== 10 Important Abbreviations ===",
188
+ abbrev_q_signs_title: "=== Q-codes ===",
189
+ abbrev_cw_signs_title: "=== CW Abbreviations ===",
190
+ abbrev_format: "%<name>s: %<morse_code>s\n Japanese: %<meaning_ja>s\n English: %<meaning_en>s",
191
+ quiz_char_start: <<~QSTART,
192
+
193
+ === Random Quiz (Characters) ===
194
+ 10 questions from A-Z,0-9.
195
+ We'll show Morse code; guess the character.
196
+ QSTART
197
+ quiz_sound_start: <<~QSTART,
198
+
199
+ === Random Quiz (Sound) ===
200
+ 10 questions from A-Z,0-9.
201
+ Identify the character from the tone.
202
+ QSTART
203
+ quiz_char_question: ->(i){ "Question #{i+1}: Which character is this Morse code?" },
204
+ quiz_sound_question: ->(i){ "Question #{i+1}: Listen to the tone. Which character?" },
205
+ quiz_correct: "Correct!",
206
+ quiz_incorrect: ->(answer){ "Wrong. The correct answer was #{answer}." },
207
+ quiz_result: ->(count){ "Quiz finished! You got #{count}/10 correct.\nPress Enter to return." },
208
+ press_enter_return: "Press Enter to return to the main menu."
209
+ }
210
+ }.freeze
211
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Morsby
4
+ MORSE_TABLE = {
5
+ 'A' => '.-', 'B' => '-...', 'C' => '-.-.', 'D' => '-..',
6
+ 'E' => '.', 'F' => '..-.', 'G' => '--.', 'H' => '....',
7
+ 'I' => '..', 'J' => '.---', 'K' => '-.-', 'L' => '.-..',
8
+ 'M' => '--', 'N' => '-.', 'O' => '---', 'P' => '.--.',
9
+ 'Q' => '--.-', 'R' => '.-.', 'S' => '...', 'T' => '-',
10
+ 'U' => '..-', 'V' => '...-', 'W' => '.--', 'X' => '-..-',
11
+ 'Y' => '-.--', 'Z' => '--..',
12
+ '0' => '-----', '1' => '.----', '2' => '..---', '3' => '...--',
13
+ '4' => '....-', '5' => '.....', '6' => '-....', '7' => '--...',
14
+ '8' => '---..', '9' => '----.'
15
+ }.freeze
16
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Morsby
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ # 和文モールス符号
4
+ # 基本清音に加え、濁音・半濁音付きの仮名も定義
5
+ # 濁音は".." + 清音符号
6
+ # 半濁音は"..-" + 清音符号
7
+
8
+ module Morsby
9
+ WABUN_TABLE = {
10
+ # 清音
11
+ 'ア' => '--.--',
12
+ 'イ' => '.-',
13
+ 'ウ' => '..-',
14
+ 'エ' => '-.-..',
15
+ 'オ' => '.---.',
16
+
17
+ 'カ' => '-.-',
18
+ 'キ' => '-.-.-',
19
+ 'ク' => '---.-',
20
+ 'ケ' => '-.-.',
21
+ 'コ' => '----',
22
+
23
+ 'サ' => '-...',
24
+ 'シ' => '--.-.',
25
+ 'ス' => '-.-.-.',
26
+ 'セ' => '--.-..',
27
+ 'ソ' => '-.-.--',
28
+
29
+ 'タ' => '-',
30
+ 'チ' => '.-.-',
31
+ 'ツ' => '..-..',
32
+ 'テ' => '.-.---',
33
+ 'ト' => '..--.',
34
+
35
+ 'ナ' => '.-.',
36
+ 'ニ' => '-.-.--',
37
+ 'ヌ' => '....',
38
+ 'ネ' => '--.-',
39
+ 'ノ' => '..---',
40
+
41
+ 'ハ' => '-...-',
42
+ 'ヒ' => '--..-',
43
+ 'フ' => '----.',
44
+ 'ヘ' => '-...',
45
+ 'ホ' => '-..',
46
+
47
+ 'マ' => '-..-',
48
+ 'ミ' => '..-.-',
49
+ 'ム' => '-.',
50
+ 'メ' => '-...-.',
51
+ 'モ' => '-..--',
52
+
53
+ 'ヤ' => '.-...',
54
+ 'ユ' => '..--..',
55
+ 'ヨ' => '.--..',
56
+
57
+ 'ラ' => '...',
58
+ 'リ' => '--.--',
59
+ 'ル' => '-....',
60
+ 'レ' => '---',
61
+ 'ロ' => '.-.-.',
62
+
63
+ 'ワ' => '.-..',
64
+ 'ヰ' => '.--.-',
65
+ 'ヱ' => '.-..-',
66
+ 'ヲ' => '.---',
67
+ 'ン' => '.-.-',
68
+
69
+ # 濁音(清音に".."を前置)
70
+ 'ガ' => '..' + '-.-', # ガ(カに濁点)
71
+ 'ギ' => '..' + '-.-.-',
72
+ 'グ' => '..' + '---.-',
73
+ 'ゲ' => '..' + '-.-.',
74
+ 'ゴ' => '..' + '----',
75
+
76
+ 'ザ' => '..' + '-...',
77
+ 'ジ' => '..' + '--.-.',
78
+ 'ズ' => '..' + '-.-.-.',
79
+ 'ゼ' => '..' + '--.-..',
80
+ 'ゾ' => '..' + '-.-.--',
81
+
82
+ 'ダ' => '..' + '-',
83
+ 'ヂ' => '..' + '.-.-',
84
+ 'ヅ' => '..' + '..-..',
85
+ 'デ' => '..' + '.-.---',
86
+ 'ド' => '..' + '..--.',
87
+
88
+ 'バ' => '..' + '-...-',
89
+ 'ビ' => '..' + '--..-',
90
+ 'ブ' => '..' + '----.',
91
+ 'ベ' => '..' + '-...',
92
+ 'ボ' => '..' + '-..',
93
+
94
+ # 半濁音(清音に"..-"を前置)
95
+ 'パ' => '..-' + '-...-',
96
+ 'ピ' => '..-' + '--..-',
97
+ 'プ' => '..-' + '----.',
98
+ 'ペ' => '..-' + '-...',
99
+ 'ポ' => '..-' + '-..'
100
+ }
101
+ end
data/lib/morsby.rb ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "morsby/version"
4
+ require_relative "morsby/cli"
5
+
6
+ module Morsby
7
+ def self.version
8
+ Morsby::VERSION
9
+ end
10
+
11
+ def self.run(argv)
12
+ CLI.new.run(argv)
13
+ end
14
+ end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: morsby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - oguressive
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-12-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: nkf
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: A tool to learn Morse code, including alphabets, digits, punctuation,
28
+ Q-codes, CW abbreviations, and Wabun Morse. Provides quizzes and bilingual messages.
29
+ email:
30
+ - oguressive.dev@gmail.com
31
+ executables:
32
+ - morsby
33
+ extensions: []
34
+ extra_rdoc_files: []
35
+ files:
36
+ - CHANGELOG.md
37
+ - README.md
38
+ - bin/morsby
39
+ - lib/morsby.rb
40
+ - lib/morsby/abbreviations.rb
41
+ - lib/morsby/cli.rb
42
+ - lib/morsby/messages.rb
43
+ - lib/morsby/morse_table.rb
44
+ - lib/morsby/version.rb
45
+ - lib/morsby/wabun_table.rb
46
+ homepage: https://github.com/oguressive/morsby
47
+ licenses:
48
+ - MIT
49
+ metadata:
50
+ changelog_uri: https://github.com/oguressive/morsby/blob/master/CHANGELOG.md
51
+ source_code_uri: https://github.com/oguressive/morsby/
52
+ rubygems_mfa_required: 'true'
53
+ post_install_message:
54
+ rdoc_options: []
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '3.1'
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ requirements: []
68
+ rubygems_version: 3.5.22
69
+ signing_key:
70
+ specification_version: 4
71
+ summary: Morse code learning and practice tool
72
+ test_files: []