jlpt 1.0.0 → 1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 351c7b81b049e4ef39a34cacf7d20e1d7ce04f1d302b7ed0033f62d48dd6eef3
4
- data.tar.gz: 903b1e3d8e7b5054a20ae4cb532325cd823dfe0e9de98800ec9705acd80b8651
3
+ metadata.gz: 589a9e7366fdbd813dda518ecf956168a94fe5290784dee57f2e675e97ca536f
4
+ data.tar.gz: 6cce29bc0a1388f9304f6423670d7513a061b053c1a144e59d85cf565c6ab4ef
5
5
  SHA512:
6
- metadata.gz: 6b5c45194f1469bc1c9e2345b8ea82766a36aa0d21e276f696baa560c7f02a1e4b57f252b9998d1d8e8cf15a2ee1ace6cda520c242ba5e39462fd413b5cb8567
7
- data.tar.gz: b41d13beb80bcc12238ed986a5c516f5c3d7ea38a5fd2be6e994c39bdf10ffa62c1c0ab023bf0307bdc74ffdc44ff30b7054aba84fce6a7197db7eb585f8ea96
6
+ metadata.gz: b7931f4110fe6090c93843a0c594d764d01c7f854bdd661aa3ab23daac4e38e5da9525d15960256e454fd6fa1f22269700bd6ff92ded603f2c4535acda223f37
7
+ data.tar.gz: 6d450ed73830940157be8354f95a38060e1a502ad441c5d04f4f4d884d1f9549fd192f4bd1ef0f4f89d1f7815afe50788f65b722dec71d3a83b10aaa6f8abcaf
data/README.ja.md CHANGED
@@ -44,7 +44,7 @@ JLPT Gemは、日本語テキストの形態素解析、語彙および漢字の
44
44
  `Gemfile` に以下を追加してください:
45
45
 
46
46
  ```ruby
47
- gem 'jlpt', '~> 1.0.0'
47
+ gem 'jlpt', '~> 1.1.0'
48
48
  ```
49
49
 
50
50
  その後、以下のコマンドを実行します:
@@ -9,9 +9,15 @@ module JLPT
9
9
  ONOMATOPOEIA_PATTERNS = %w[
10
10
  どきどき わくわく ぺらぺら にこにこ ふわふわ ぎっしり
11
11
  ギリギリ イライラ キラキラ ドキドキ ニコニコ ペラペラ
12
- もちもち すらすら どんどん だんだん いろいろ
12
+ もちもち すらすら どんどん だんだん いろいろ ぴったり
13
+ すっきり さっぱり のんびり うっとり がっかり しっかり
14
+ はっきり こっそり ゆっくり びっくり ばっちり めっきり
15
+ うろうろ ぶらぶら ごちゃごちゃ そわそわ すやすや ぐっすり
13
16
  ].freeze
14
17
 
18
+ # Regex for 2-mora repeated reduplicated patterns (ABAB)
19
+ REDUPLICATED_REGEX = /^(\p{Hiragana}{2}|\p{Katakana}{2})\1$/.freeze
20
+
15
21
  class << self
16
22
  # Extract onomatopoeia words from Japanese text
17
23
  #
@@ -22,6 +28,12 @@ module JLPT
22
28
  return [] if cleaned.empty?
23
29
 
24
30
  matches = ONOMATOPOEIA_PATTERNS.select { |word| cleaned.include?(word) }
31
+ morphemes = Tokenizer.lemmata(cleaned)
32
+
33
+ morphemes.each do |m|
34
+ matches << m if m.match?(REDUPLICATED_REGEX) && m.length == 4
35
+ end
36
+
25
37
  matches.uniq
26
38
  end
27
39
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'json'
4
+
3
5
  module JLPT
4
6
  # Pitch Accent Profiler and Pattern Lookup.
5
7
  #
@@ -7,16 +9,9 @@ module JLPT
7
9
  # for Japanese vocabulary words.
8
10
  #
9
11
  module PitchAccent
10
- # Built-in pitch accent database for common words
11
- ACCENT_MAP = {
12
- '学校' => { type: :odaka, pattern: 0 },
13
- '私' => { type: :heiban, pattern: 0 },
14
- '日本' => { type: :atamadaka, pattern: 1 },
15
- '猫' => { type: :atamadaka, pattern: 1 },
16
- '犬' => { type: :atamadaka, pattern: 2 },
17
- '本' => { type: :atamadaka, pattern: 1 },
18
- '先生' => { type: :nakadaka, pattern: 3 }
19
- }.freeze
12
+ DATA_PATH = File.expand_path('../data/pitch_accent.json', __dir__)
13
+ MUTEX = Mutex.new
14
+ @dataset = nil
20
15
 
21
16
  class << self
22
17
  # Lookup pitch accent for a vocabulary word
@@ -26,7 +21,14 @@ module JLPT
26
21
  def accent_for(word)
27
22
  return nil if word.nil? || word.to_s.strip.empty?
28
23
 
29
- ACCENT_MAP[word.to_s.strip] || { type: :heiban, pattern: 0 }
24
+ w = word.to_s.strip
25
+ dataset = load_dataset!
26
+
27
+ if dataset.key?(w)
28
+ { type: dataset[w]['type'].to_sym, pattern: dataset[w]['pattern'] }
29
+ else
30
+ { type: :heiban, pattern: 0 }
31
+ end
30
32
  end
31
33
 
32
34
  # Profile pitch accent patterns in Japanese text
@@ -46,6 +48,18 @@ module JLPT
46
48
  end
47
49
  result
48
50
  end
51
+
52
+ private
53
+
54
+ def load_dataset!
55
+ return @dataset if @dataset
56
+
57
+ MUTEX.synchronize do
58
+ return @dataset if @dataset
59
+
60
+ @dataset = File.exist?(DATA_PATH) ? JSON.parse(File.read(DATA_PATH)) : {}
61
+ end
62
+ end
49
63
  end
50
64
  end
51
65
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'json'
4
+
3
5
  module JLPT
4
6
  # Text Simplifier and Beginner Synonym Recommender.
5
7
  #
@@ -7,16 +9,9 @@ module JLPT
7
9
  # N5/N4/N3 synonym alternatives for Japanese language learners.
8
10
  #
9
11
  module Simplifier
10
- SIMPLIFICATIONS = {
11
- '著しい' => { reading: 'いちじるしい', suggestions: %w[大きい 目立つ] },
12
- '著しく' => { reading: 'いちじるしく', suggestions: %w[大きく 目立って] },
13
- '未曽有' => { reading: 'みぞう', suggestions: %w[今までにない 初めての] },
14
- '浸透' => { reading: 'しんとう', suggestions: %w[広がる 伝わる] },
15
- '阻害' => { reading: 'そがい', suggestions: %w[邪魔する 妨げる] },
16
- '急速' => { reading: 'きゅうそく', suggestions: %w[とても速い 急に] },
17
- '懸念' => { reading: 'けねん', suggestions: %w[心配 不安] },
18
- '普及' => { reading: 'ふきゅう', suggestions: %w[広まる みんなが使う] }
19
- }.freeze
12
+ DATA_PATH = File.expand_path('../data/simplifications.json', __dir__)
13
+ MUTEX = Mutex.new
14
+ @dataset = nil
20
15
 
21
16
  class << self
22
17
  # Analyze text and return simplification suggestions for high-level words
@@ -27,7 +22,8 @@ module JLPT
27
22
  cleaned = Preprocessor.clean(text)
28
23
  return [] if cleaned.empty?
29
24
 
30
- SIMPLIFICATIONS.filter_map do |word, data|
25
+ dataset = load_dataset!
26
+ dataset.filter_map do |word, data|
31
27
  build_suggestion(word, data) if cleaned.include?(word)
32
28
  end
33
29
  end
@@ -39,10 +35,20 @@ module JLPT
39
35
  {
40
36
  word: word,
41
37
  level: level,
42
- reading: data[:reading],
43
- suggestions: data[:suggestions]
38
+ reading: data['reading'],
39
+ suggestions: data['suggestions']
44
40
  }
45
41
  end
42
+
43
+ def load_dataset!
44
+ return @dataset if @dataset
45
+
46
+ MUTEX.synchronize do
47
+ return @dataset if @dataset
48
+
49
+ @dataset = File.exist?(DATA_PATH) ? JSON.parse(File.read(DATA_PATH)) : {}
50
+ end
51
+ end
46
52
  end
47
53
  end
48
54
  end
@@ -1,23 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'json'
4
+
3
5
  module JLPT
4
6
  # Kanji Details Inspector.
5
7
  #
6
- # Provides stroke count, radical, On'yomi, Kun'yomi, English meanings, and JLPT levels for Kanji.
8
+ # Provides stroke count, radical, On'yomi, Kun'yomi, and JLPT levels for Kanji.
7
9
  #
8
10
  module KanjiDetails
9
- KANJI_DATA = {
10
- '私' => { character: '私', strokes: 7, radical: '禾', onyomi: %w[シ], kunyomi: %w[わたし], level: :n5 },
11
- '学' => { character: '学', strokes: 8, radical: '子', onyomi: %w[ガク], kunyomi: %w[まな.ぶ], level: :n5 },
12
- '校' => { character: '校', strokes: 10, radical: '木', onyomi: %w[コウ], kunyomi: [], level: :n5 },
13
- '日' => { character: '日', strokes: 4, radical: '日', onyomi: %w[ニチ], kunyomi: %w[ひ], level: :n5 },
14
- '本' => { character: '本', strokes: 5, radical: '木', onyomi: %w[ホン], kunyomi: %w[もと], level: :n5 },
15
- '語' => { character: '語', strokes: 14, radical: '言', onyomi: %w[ゴ], kunyomi: %w[かた.る], level: :n5 },
16
- '食' => { character: '食', strokes: 9, radical: '食', onyomi: %w[ショク], kunyomi: %w[た.べる], level: :n5 },
17
- '飲' => { character: '飲', strokes: 12, radical: '食', onyomi: %w[イン], kunyomi: %w[の.む], level: :n5 },
18
- '行' => { character: '行', strokes: 6, radical: '行', onyomi: %w[コウ], kunyomi: %w[い.く], level: :n5 },
19
- '来' => { character: '来', strokes: 7, radical: '木', onyomi: %w[ライ], kunyomi: %w[く.る], level: :n5 }
20
- }.freeze
11
+ DATA_PATH = File.expand_path('../data/kanji_details.json', __dir__)
12
+ MUTEX = Mutex.new
13
+ @dataset = nil
21
14
 
22
15
  class << self
23
16
  # Lookup Kanji details for a single character
@@ -30,8 +23,7 @@ module JLPT
30
23
  kanji_char = char.to_s.strip[0]
31
24
  return nil unless kanji_char.match?(/[\u4E00-\u9FFF]/)
32
25
 
33
- level = Dictionary.kanji_level(kanji_char) || :out_of_jlpt
34
- KANJI_DATA[kanji_char] || default_kanji_details(kanji_char, level)
26
+ fetch_details(kanji_char)
35
27
  end
36
28
 
37
29
  # Get details for all unique kanji in text
@@ -45,11 +37,43 @@ module JLPT
45
37
 
46
38
  private
47
39
 
40
+ def fetch_details(char)
41
+ dataset = load_dataset!
42
+ level = Dictionary.kanji_level(char) || :out_of_jlpt
43
+
44
+ if dataset.key?(char)
45
+ format_entry(dataset[char])
46
+ else
47
+ default_kanji_details(char, level)
48
+ end
49
+ end
50
+
51
+ def format_entry(entry)
52
+ {
53
+ character: entry['character'],
54
+ strokes: entry['strokes'],
55
+ radical: entry['radical'],
56
+ onyomi: entry['onyomi'],
57
+ kunyomi: entry['kunyomi'],
58
+ level: entry['level'].to_sym
59
+ }
60
+ end
61
+
62
+ def load_dataset!
63
+ return @dataset if @dataset
64
+
65
+ MUTEX.synchronize do
66
+ return @dataset if @dataset
67
+
68
+ @dataset = File.exist?(DATA_PATH) ? JSON.parse(File.read(DATA_PATH)) : {}
69
+ end
70
+ end
71
+
48
72
  def default_kanji_details(char, level)
49
73
  {
50
74
  character: char,
51
75
  strokes: 8,
52
- radical: 'undefined',
76
+ radical: char,
53
77
  onyomi: [],
54
78
  kunyomi: [],
55
79
  level: level