asciidoc-pubkit 0.1.1 → 0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b5e89872635e44464421539669ea3fb4a76c886a3adae9f5ca1df98fd864d05c
4
- data.tar.gz: bf081702caf7eca34423eea571fd23ad9dfffc89ed11c9b1d013dd84fb25d57c
3
+ metadata.gz: de07af1758fdba08a7099b9e66f63b14084d0dad6cba8437498f0ddd0577b425
4
+ data.tar.gz: 8474d883c10c23f1221ff85cbd023d781c84f93dd55436a542c0d304c0a8f424
5
5
  SHA512:
6
- metadata.gz: 93bae7f5ef964afa60b0d6eee95b332270907df107dedae820c09fbbc1829d0d88077df96c20eaff8d9654f31ff6e47390517d1922b6486186dfa04ff17d107a
7
- data.tar.gz: 5ab456dedf2c322836c827e00a0e2443b3bb9709202d88a0e82203561af98c6953debc601c799355f4df45b744d645f7c4cb670b812c0d7240c374973de09f7c
6
+ metadata.gz: 6983524a7967131b469360bebd417125d7eea14cdf8054d14c928940528d685ee50fd0c402ca354073a55e643217ed931ddda3ca3e402d252d02e4030b7b3a9e
7
+ data.tar.gz: 8e8111fea8d32dfb1449c48cfc8d8f2df22e58dec14a44a55c6dcb6596a6bd3e87aa86fbd596cfc332a6ca49c9d1452f5dd34b23126137d9359a081585e1ae56
data/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.2 — Released
4
+
5
+ - Package default Japanese review rules as a validated UTF-8 YAML file.
6
+ - Support custom rule files through `review scan --rules` and `review.rules`.
7
+ - Save resolved rules in sessions for reproducible prompts and verification.
8
+ - Add concept, distinction, and negative meaning review candidates.
9
+ - Add a Make target for running a local checkout with arbitrary CLI arguments.
10
+ - Require a new review session when upgrading from earlier tool versions.
11
+
3
12
  ## 0.1.1 — Released
4
13
 
5
14
  - Add contextual phrases, compound nouns, and potential and causative verb forms.
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  ![](https://img.shields.io/badge/status-Work%20In%20Progress-8A2BE2)
2
2
  ![GitHub tag (latest SemVer)](https://img.shields.io/github/v/tag/cybergarage/asciidoc-pubkit)
3
3
  [![Gem Version](https://img.shields.io/gem/v/asciidoc-pubkit.svg)](https://rubygems.org/gems/asciidoc-pubkit)
4
+ [![Build Status](https://github.com/cybergarage/asciidoc-pubkit/actions/workflows/test.yml/badge.svg)](https://github.com/cybergarage/asciidoc-pubkit/actions/workflows/test.yml)
4
5
 
5
6
  # asciidoc-pubkit
6
7
 
@@ -59,7 +60,7 @@ Add the gem to your project's `Gemfile` to manage its version with Bundler:
59
60
 
60
61
  ```ruby
61
62
  source 'https://rubygems.org'
62
- gem 'asciidoc-pubkit', '~> 0.1.1'
63
+ gem 'asciidoc-pubkit', '~> 0.1.2'
63
64
  ```
64
65
 
65
66
  Then install dependencies and run the CLI through Bundler:
@@ -81,7 +82,7 @@ git clone https://github.com/cybergarage/asciidoc-pubkit.git
81
82
  cd asciidoc-pubkit
82
83
  bundle install
83
84
  gem build asciidoc-pubkit.gemspec
84
- gem install ./asciidoc-pubkit-0.1.1.gem
85
+ gem install ./asciidoc-pubkit-0.1.2.gem
85
86
  asciidoc-pubkit --version
86
87
  ```
87
88
 
@@ -92,6 +93,34 @@ For a small trial, use `examples/book.adoc` as the scan input. Its Japanese
92
93
  paragraphs deliberately contain review candidates; its code block must remain
93
94
  unchanged.
94
95
 
96
+ ## Run from a local checkout
97
+
98
+ Use the `run` Make target to execute the checkout without installing the
99
+ asciidoc-pubkit gem. Ruby dependencies and, for the default tokenizer, MeCab and
100
+ UTF-8 IPADIC must already be installed.
101
+
102
+ ```sh
103
+ make run ARGS="--version"
104
+ make run ARGS="review scan examples/book.adoc"
105
+ make run ARGS='review scan "manuscripts/my book.adoc"'
106
+ ```
107
+
108
+ With no `ARGS`, `make run` displays CLI help. Set `RUBY` to choose another Ruby
109
+ executable. `ARGS` is shell command-line text; quote paths containing spaces and
110
+ use only trusted arguments.
111
+
112
+ To run from a manuscript directory, select the checkout's Makefile with `-f`.
113
+ Relative manuscript paths and output paths remain relative to your current
114
+ working directory:
115
+
116
+ ```sh
117
+ make -f "$HOME/Src/asciidoc-pubkit/Makefile" run ARGS="review scan book.adoc"
118
+ ```
119
+
120
+ Use `ARGS` instead of `make review scan book.adoc`: Make interprets positional
121
+ words as build targets, not CLI arguments. Avoid `make -C` when manuscript paths
122
+ should remain relative to the current directory, because it changes directories.
123
+
95
124
  ## Install the morphological analyzer (0.1.1 and later)
96
125
 
97
126
  On macOS with Homebrew:
@@ -298,12 +327,12 @@ reports analyzer changes instead of treating results from different dictionaries
298
327
  as directly comparable. Prompt generation uses saved evidence and does not need
299
328
  MeCab. Changed rules or dictionary settings require a new scan.
300
329
 
301
- Sessions from 0.1.0 are not compatible with 0.1.1. Keep the original baseline for
330
+ Sessions from earlier tool versions are not compatible with 0.1.2. Keep the original baseline for
302
331
  an ongoing review and finish it with the original version, or start a new review
303
332
  pass in a different directory:
304
333
 
305
334
  ```sh
306
- asciidoc-pubkit review scan book.adoc --output .pubkit/review-0.1.1
335
+ asciidoc-pubkit review scan book.adoc --output .pubkit/review-0.1.2
307
336
  ```
308
337
 
309
338
  Severity describes review priority, not proof of an error. There is no AI-authorship
@@ -341,3 +370,69 @@ GitHub Actions is configured for Ruby 3.2, 3.3, 3.4, and 4.0 on Linux.
341
370
  Copyright 2026 CyberGarage.
342
371
 
343
372
  Licensed under the Apache License, Version 2.0. See [LICENSE](LICENSE).
373
+
374
+ ## Customize review rules
375
+
376
+ The UTF-8 YAML file [`data/review-rules.ja.yml`](data/review-rules.ja.yml) is
377
+ included in the gem and loaded by default. Edit that file when running a local
378
+ checkout, or copy it to a project-owned file for custom rules. No Ruby changes
379
+ are required to update candidate terms.
380
+
381
+ ```sh
382
+ asciidoc-pubkit review scan book.adoc --rules ./review-rules.yml
383
+ make run ARGS="review scan book.adoc --rules ./review-rules.yml"
384
+ ```
385
+
386
+ For an installed gem, copy the default file with:
387
+
388
+ ```sh
389
+ ruby -rasciidoc_pubkit -e 'puts File.read(AsciidocPubkit::RuleSet::DEFAULT_PATH)' > review-rules.yml
390
+ ```
391
+
392
+ Alternatively, configure a path in `.asciidoc-pubkit.yml`:
393
+
394
+ ```yaml
395
+ review:
396
+ rules: review-rules.yml
397
+ ```
398
+
399
+ Precedence is `--rules`, then `review.rules`, then the packaged default.
400
+ CLI paths are relative to the current working directory; configuration paths
401
+ are relative to the configuration file. A custom file replaces the entire rule
402
+ set; it is not merged with defaults. Start by copying the standard file.
403
+
404
+ ### Rule file format (schema version 1)
405
+
406
+ All top-level fields below are required. Unknown keys and invalid types are
407
+ rejected. YAML aliases and object tags are not supported.
408
+
409
+ | Field | Format and behavior |
410
+ | --- | --- |
411
+ | `schema_version` | Integer `1` |
412
+ | `terms` | Mapping containing all five categories listed below |
413
+ | `verbs` | Mapping from canonical verb forms to nonempty arrays of MeCab/IPADIC dictionary forms; each dictionary form belongs to only one canonical form |
414
+ | `sahen` | Array of nouns matched with a following `する` verb |
415
+ | `negative_only` | Array of canonical predicates restricted to negative forms; use the noun plus `する` for sahen predicates |
416
+ | `compound_nouns` | Array of terms matched across contiguous noun tokens; each must also appear in `abstract-reference.terms` |
417
+
418
+ Each `terms` category must contain `terms` (an array of unique nonempty strings)
419
+ and `question` (a nonempty review instruction string). The required categories
420
+ are `abstract-reference`, `weak-predicate`, `vague-degree`, `contextual-phrase`,
421
+ and `generic-framing`. Empty term arrays disable that category's literal
422
+ candidates. Empty `verbs`, `sahen`, and `compound_nouns` collections disable their
423
+ respective morphological matchers. Keep `negative_only` consistent with the
424
+ configured predicates.
425
+
426
+ In literal mode, all category term lists use exact phrase matching. In MeCab
427
+ mode, abstract nouns and degree adjectives use dictionary forms, while predicates
428
+ use `verbs` and `sahen`; add a predicate's desired literal surface to
429
+ `weak-predicate.terms` as well if literal mode should detect it. Contextual and
430
+ generic framing phrases use literal matching in both modes. Questions apply to
431
+ both detectors. Glossary, style, repeated-ending checks, inline exclusions, and
432
+ morphological suffix handling remain implemented in Ruby.
433
+
434
+ A scan saves the resolved rule contents and source path in `manifest.json`.
435
+ Prompt generation and verification use the saved contents, even if the original
436
+ YAML file is subsequently edited or removed. Start a new session to apply rule
437
+ changes. Older sessions without a rule snapshot fall back to the currently
438
+ installed default file; start a new session for reproducible custom-rule reviews.
@@ -0,0 +1,123 @@
1
+ ---
2
+ schema_version: 1
3
+ terms:
4
+ abstract-reference:
5
+ terms:
6
+ - コスト
7
+ - 境界
8
+ - 契約
9
+ - 観点
10
+ - 土台
11
+ - 橋渡し
12
+ - 入口
13
+ - 記述
14
+ - 場所
15
+ - 意図
16
+ - 役割
17
+ - 一続き
18
+ - 根拠
19
+ - 部品
20
+ - 開発者
21
+ - 概念
22
+ question: Identify the concrete referent, components, or measurable work. Keep
23
+ established technical meanings.
24
+ weak-predicate:
25
+ terms:
26
+ - 利用します
27
+ - 整理します
28
+ - 扱います
29
+ - 示します
30
+ - 変わります
31
+ - 把握します
32
+ - 分けられます
33
+ - そろえます
34
+ - まとまっています
35
+ - 加えます
36
+ - 探します
37
+ - 到達しません
38
+ - 扱いません
39
+ - そろいます
40
+ - 選べます
41
+ - 成り立たせています
42
+ - 確かめます
43
+ - 書き換える
44
+ - 絞れます
45
+ - 渡します
46
+ - あります
47
+ - 意味しません
48
+ question: Check whether the purpose, operation, or result is clear from the surrounding
49
+ paragraph. Preserve negation and conditions.
50
+ vague-degree:
51
+ terms:
52
+ - 浅い
53
+ - 深い
54
+ question: Identify the concrete depth, level, scope, or comparison. Keep literal
55
+ measurements and established technical meanings.
56
+ contextual-phrase:
57
+ terms:
58
+ - これらを
59
+ - であることだけでは
60
+ - あるものとします
61
+ - わけではありません
62
+ - 別です
63
+ question: Check the referent, assumption, or qualification against the surrounding
64
+ explanation. Preserve conditions and negation.
65
+ generic-framing:
66
+ terms:
67
+ - 重要なのは
68
+ - ポイントは
69
+ - 本章では
70
+ - ここでは
71
+ - まとめると
72
+ question: Check whether this framing adds useful scope or information instead
73
+ of repeating the explanation.
74
+ verbs:
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
+ 確かめる:
102
+ - 確かめる
103
+ 書き換える:
104
+ - 書き換える
105
+ 絞る:
106
+ - 絞る
107
+ - 絞れる
108
+ 渡す:
109
+ - 渡す
110
+ ある:
111
+ - ある
112
+ sahen:
113
+ - 利用
114
+ - 整理
115
+ - 把握
116
+ - 到達
117
+ - 意味
118
+ negative_only:
119
+ - 到達する
120
+ - 意味する
121
+ compound_nouns:
122
+ - 一続き
123
+ - 開発者
@@ -36,6 +36,7 @@ module AsciidocPubkit
36
36
  if command == 'scan'
37
37
  opts.on('--only FILE', 'Review one included file in the book context') { |v| options[:only] = v }
38
38
  opts.on('--config FILE', 'Use an explicit YAML configuration') { |v| options[:config] = v }
39
+ opts.on('--rules FILE', 'Replace default review rules with a YAML rule set') { |v| options[:rules] = v }
39
40
  opts.on('--base-dir DIR', 'Set the Asciidoctor base directory') { |v| options[:base_dir] = v }
40
41
  opts.on('--lang LANG', 'Prose language (ja only)') { |v| options[:language] = v }
41
42
  opts.on('--tokenizer NAME', 'mecab (default) or literal (limited phrase matching)') { |v| options[:tokenizer] = v }
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AsciidocPubkit
4
+ class RuleSet
5
+ DEFAULT_PATH = File.expand_path('../../data/review-rules.ja.yml', __dir__)
6
+ CATEGORIES = %w[abstract-reference weak-predicate vague-degree contextual-phrase generic-framing].freeze
7
+ KEYS = %w[schema_version terms verbs sahen negative_only compound_nouns].freeze
8
+
9
+ def self.load(path = DEFAULT_PATH)
10
+ validate(YAML.safe_load(AsciidocPubkit.read_text(path), permitted_classes: [], aliases: false))
11
+ rescue Psych::Exception => e
12
+ raise Error, "Invalid rule YAML in #{path}: #{e.message}"
13
+ end
14
+
15
+ def self.mapping(value, keys, label)
16
+ unless value.is_a?(Hash) && (value.keys - keys).empty? && (keys - value.keys).empty?
17
+ raise Error, "#{label} must contain exactly these keys: #{keys.join(', ')}."
18
+ end
19
+ end
20
+
21
+ def self.strings(value, label)
22
+ unless value.is_a?(Array) && value.all? { |s| s.is_a?(String) && !s.strip.empty? } && value.uniq == value
23
+ raise Error, "#{label} must be an array of unique nonempty strings."
24
+ end
25
+ end
26
+
27
+ def self.validate(data)
28
+ mapping(data, KEYS, 'Rule set')
29
+ raise Error, 'Rule schema_version must be integer 1.' unless data['schema_version'].is_a?(Integer) && data['schema_version'] == 1
30
+ mapping(data['terms'], CATEGORIES, 'Rule terms')
31
+ data['terms'].each do |category, entry|
32
+ mapping(entry, %w[terms question], category)
33
+ strings(entry['terms'], "#{category}.terms")
34
+ raise Error, "#{category}.question must be a nonempty string." unless entry['question'].is_a?(String) && !entry['question'].strip.empty?
35
+ end
36
+ verbs = data['verbs']
37
+ raise Error, 'verbs must be a mapping of canonical forms to lemma arrays.' unless verbs.is_a?(Hash)
38
+ verbs.each do |canonical, forms|
39
+ raise Error, 'Verb canonical forms must be nonempty strings.' unless canonical.is_a?(String) && !canonical.strip.empty?
40
+ strings(forms, "verbs.#{canonical}")
41
+ raise Error, "verbs.#{canonical} must contain at least one lemma." if forms.empty?
42
+ end
43
+ aliases = verbs.values.flatten
44
+ raise Error, 'Verb lemmas must have only one canonical form.' unless aliases.uniq == aliases
45
+ %w[sahen negative_only compound_nouns].each { |key| strings(data[key], key) }
46
+ canonical_forms = verbs.keys + data['sahen'].map { |noun| noun + 'する' }
47
+ raise Error, 'negative_only must refer to configured canonical predicates.' unless (data['negative_only'] - canonical_forms).empty?
48
+ raise Error, 'compound_nouns must also appear in abstract-reference terms.' unless (data['compound_nouns'] - data['terms']['abstract-reference']['terms']).empty?
49
+ data
50
+ end
51
+ end
52
+ end
@@ -3,30 +3,14 @@
3
3
  module AsciidocPubkit
4
4
  class Rules
5
5
  INLINE = /`[^`\n]*`|\+\+\+.*?\+\+\+|\+\+[^\n]*?\+\+|(?<!\w)\+[^+\n]+\+|「[^」\n]*」|『[^』\n]*』|\{[^}\n]+\}|<<[^>\n]+>>|\[\[[^\]\n]+\]\]|(?:link|xref|image|footnote|pass):[^\s\[]*\[[^\]\n]*\]|https?:\/\/[^\s\[\]<>]+(?:\[[^\]\n]*\])?/m
6
- TERMS = {
7
- 'abstract-reference' => [%w[コスト 境界 契約 観点 土台 橋渡し 入口 記述 場所 意図 役割 一続き 根拠 部品 開発者], 'Identify the concrete referent, components, or measurable work. Keep established technical meanings.'],
8
- 'weak-predicate' => [%w[利用します 整理します 扱います 示します 変わります 把握します 分けられます そろえます まとまっています 加えます 探します 到達しません 扱いません そろいます 選べます 成り立たせています 確かめます 書き換える 絞れます 渡します あります], 'Check whether the purpose, operation, or result is clear from the surrounding paragraph. Preserve negation and conditions.'],
9
- 'vague-degree' => [%w[浅い 深い], 'Identify the concrete depth, level, scope, or comparison. Keep literal measurements and established technical meanings.'],
10
- 'contextual-phrase' => [%w[これらを であることだけでは あるものとします わけではありません], 'Check the referent, assumption, or qualification against the surrounding explanation. Preserve conditions and negation.'],
11
- 'generic-framing' => [%w[重要なのは ポイントは 本章では ここでは まとめると], 'Check whether this framing adds useful scope or information instead of repeating the explanation.']
12
- }.freeze
13
- VERBS = {
14
- '扱う' => %w[扱う], '示す' => %w[示す], '変わる' => %w[変わる],
15
- '分ける' => %w[分ける], 'そろえる' => %w[そろえる 揃える],
16
- 'まとまる' => %w[まとまる 纏まる], '加える' => %w[加える],
17
- '探す' => %w[探す], 'そろう' => %w[そろう 揃う],
18
- '選ぶ' => %w[選ぶ 選べる], '成り立つ' => %w[成り立つ],
19
- '確かめる' => %w[確かめる], '書き換える' => %w[書き換える],
20
- '絞る' => %w[絞る 絞れる], '渡す' => %w[渡す], 'ある' => %w[ある]
21
- }.freeze
22
- SAHEN = %w[利用 整理 把握 到達].freeze
23
-
24
6
  def self.mask(text)
25
7
  # Keep character offsets stable while excluding common inline constructs.
26
8
  text.gsub(INLINE) { |match| match.gsub(/[^\n]/, ' ') }
27
9
  end
28
10
 
29
11
  def self.scan(paragraphs, settings, tokenizer: nil)
12
+ rules = RuleSet.validate(settings.fetch('rules') { RuleSet.load })
13
+ terms = rules.fetch('terms').transform_values { |entry| entry.values_at('terms', 'question') }
30
14
  findings = []
31
15
  if settings.fetch('tokenizer', 'mecab') == 'mecab'
32
16
  tokenizer ||= Morphology.new(settings)
@@ -34,8 +18,8 @@ module AsciidocPubkit
34
18
  token_groups = tokenizer ? tokenize_paragraphs(paragraphs, tokenizer) : []
35
19
  paragraphs.each_with_index do |paragraph, index|
36
20
  text = mask(paragraph.fetch('text'))
37
- scan_morphemes(findings, paragraph, text, token_groups[index], settings) if tokenizer
38
- TERMS.each do |rule, (terms, question)|
21
+ scan_morphemes(findings, paragraph, text, token_groups[index], settings, rules, terms) if tokenizer
22
+ terms.each do |rule, (terms, question)|
39
23
  next if tokenizer && !%w[generic-framing contextual-phrase].include?(rule)
40
24
  terms.each do |term|
41
25
  next if settings.fetch('allows').include?(term)
@@ -90,8 +74,8 @@ module AsciidocPubkit
90
74
  end
91
75
  end
92
76
 
93
- def self.scan_morphemes(findings, paragraph, text, tokens, settings)
94
- phrase_ranges = TERMS['contextual-phrase'][0].flat_map do |phrase|
77
+ def self.scan_morphemes(findings, paragraph, text, tokens, settings, rules, terms)
78
+ phrase_ranges = terms['contextual-phrase'][0].flat_map do |phrase|
95
79
  text.to_enum(:scan, Regexp.new(Regexp.escape(phrase))).map do
96
80
  match = Regexp.last_match
97
81
  match.begin(0)...match.end(0)
@@ -102,26 +86,34 @@ module AsciidocPubkit
102
86
  lemma = token['lemma']
103
87
  rule = nil
104
88
  finish_index = index
105
- compound = %w[一続き 開発者].find do |term|
106
- following = tokens[index + 1]
107
- following && token['pos'] == '名詞' && following['pos'] == '名詞' &&
108
- !following['unknown'] && token['end_offset'] == following['offset'] &&
109
- token['surface'] + following['surface'] == term
89
+ compound = rules.fetch('compound_nouns').find do |term|
90
+ surface = +''
91
+ cursor = index
92
+ while (member = tokens[cursor]) && member['pos'] == '名詞' && !member['unknown']
93
+ break if cursor > index && tokens[cursor - 1]['end_offset'] != member['offset']
94
+ surface << member['surface']
95
+ break unless term.start_with?(surface)
96
+ if surface == term
97
+ finish_index = cursor
98
+ break
99
+ end
100
+ cursor += 1
101
+ end
102
+ surface == term
110
103
  end
111
104
  if compound
112
105
  lemma = compound
113
- finish_index = index + 1
114
106
  rule = 'abstract-reference'
115
- elsif token['pos'] == '名詞' && TERMS['abstract-reference'][0].include?(lemma)
107
+ elsif token['pos'] == '名詞' && terms['abstract-reference'][0].include?(lemma)
116
108
  rule = 'abstract-reference'
117
- elsif token['pos'] == '形容詞' && TERMS['vague-degree'][0].include?(lemma)
109
+ elsif token['pos'] == '形容詞' && terms['vague-degree'][0].include?(lemma)
118
110
  rule = 'vague-degree'
119
111
  finish_index = predicate_end(tokens, index, text)
120
- elsif token['pos'] == '動詞' && (entry = VERBS.find { |_canonical, forms| forms.include?(lemma) })
112
+ elsif token['pos'] == '動詞' && (entry = rules.fetch('verbs').find { |_canonical, forms| forms.include?(lemma) })
121
113
  lemma = entry[0]
122
114
  rule = 'weak-predicate'
123
115
  finish_index = predicate_end(tokens, index, text)
124
- elsif token['pos'] == '名詞' && token['pos_detail'] == 'サ変接続' && SAHEN.include?(lemma)
116
+ elsif token['pos'] == '名詞' && token['pos_detail'] == 'サ変接続' && rules.fetch('sahen').include?(lemma)
125
117
  following = tokens[index + 1]
126
118
  next unless following && following['pos'] == '動詞' && following['lemma'] == 'する' && adjacent?(token, following, text)
127
119
  lemma += 'する'
@@ -131,11 +123,11 @@ module AsciidocPubkit
131
123
  next unless rule
132
124
  members = tokens[index..finish_index]
133
125
  negative = members.any? { |member| member['pos'] == '助動詞' && %w[ない ぬ ん].include?(member['lemma']) }
134
- next if lemma == '到達する' && !negative
126
+ next if rules.fetch('negative_only').include?(lemma) && !negative
135
127
  surface = text[token['offset']...tokens[finish_index]['end_offset']]
136
128
  allows = settings.fetch('allows')
137
129
  next if [lemma, token['lemma'], surface, surface + '。'].any? { |form| allows.include?(form) }
138
- add(findings, paragraph, text, token['offset'], surface, rule, 'hint', TERMS.fetch(rule)[1])
130
+ add(findings, paragraph, text, token['offset'], surface, rule, 'hint', terms.fetch(rule)[1])
139
131
  findings.last.merge!('lemma' => lemma, 'part_of_speech' => token['pos'], 'negative' => negative,
140
132
  'detector' => 'mecab-ipadic')
141
133
  end
@@ -23,13 +23,16 @@ module AsciidocPubkit
23
23
  reject_keys(config, ['review'], 'configuration')
24
24
  review = config.fetch('review', {})
25
25
  raise Error, 'review must be a mapping.' unless review.is_a?(Hash)
26
- reject_keys(review, %w[language style glossary exclude allows attributes base_dir tokenizer mecab_command mecab_dictionary], 'review')
26
+ reject_keys(review, %w[language style glossary exclude allows attributes base_dir tokenizer mecab_command mecab_dictionary rules], 'review')
27
27
  raise Error, 'attributes must be a mapping.' unless review.fetch('attributes', {}).is_a?(Hash)
28
- %w[base_dir glossary mecab_command mecab_dictionary].each do |key|
28
+ %w[base_dir glossary mecab_command mecab_dictionary rules].each do |key|
29
29
  raise Error, "#{key} must be a nonempty path string." if review.key?(key) && (!review[key].is_a?(String) || review[key].empty?)
30
30
  end
31
31
  base = @path ? File.dirname(@path) : File.dirname(File.expand_path(entry))
32
+ rules_path = options[:rules] ? File.expand_path(options[:rules]) : (review['rules'] ? File.expand_path(review['rules'], base) : RuleSet::DEFAULT_PATH)
32
33
  @data = {
34
+ 'rules' => RuleSet.load(rules_path),
35
+ 'rules_path' => rules_path,
33
36
  'language' => options[:language] || review.fetch('language', 'ja'),
34
37
  'style' => options[:style] || review.fetch('style', 'preserve'),
35
38
  'exclude' => review.fetch('exclude', []),
@@ -9,7 +9,7 @@ require 'pathname'
9
9
  require 'optparse'
10
10
 
11
11
  module AsciidocPubkit
12
- VERSION = '0.1.1'
12
+ VERSION = '0.1.2'
13
13
  class Error < StandardError; end
14
14
 
15
15
  def self.hash_text(text)
@@ -23,6 +23,7 @@ module AsciidocPubkit
23
23
  end
24
24
  end
25
25
 
26
+ require_relative 'asciidoc_pubkit/rule_set'
26
27
  require_relative 'asciidoc_pubkit/settings'
27
28
  require_relative 'asciidoc_pubkit/document'
28
29
  require_relative 'asciidoc_pubkit/morphology'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asciidoc-pubkit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - CyberGarage
@@ -47,12 +47,14 @@ files:
47
47
  - CHANGELOG.md
48
48
  - LICENSE
49
49
  - README.md
50
+ - data/review-rules.ja.yml
50
51
  - examples/book.adoc
51
52
  - exe/asciidoc-pubkit
52
53
  - lib/asciidoc_pubkit.rb
53
54
  - lib/asciidoc_pubkit/cli.rb
54
55
  - lib/asciidoc_pubkit/document.rb
55
56
  - lib/asciidoc_pubkit/morphology.rb
57
+ - lib/asciidoc_pubkit/rule_set.rb
56
58
  - lib/asciidoc_pubkit/rules.rb
57
59
  - lib/asciidoc_pubkit/session.rb
58
60
  - lib/asciidoc_pubkit/settings.rb