simple_english 0.2.0 → 0.4.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 +4 -4
- data/README.md +61 -39
- data/docs/RULES.md +1 -1
- data/lib/simple_english/cli.rb +53 -15
- data/lib/simple_english/client/daemon.rb +225 -0
- data/lib/simple_english/client/language_tool.rb +95 -0
- data/lib/simple_english/daemon/engine.rb +40 -0
- data/lib/simple_english/{http.rb → daemon/http.rb} +10 -4
- data/lib/simple_english/{server.rb → daemon/server.rb} +113 -7
- data/lib/simple_english/{extractor.rb → lint/extractor.rb} +6 -1
- data/lib/simple_english/lint/finding.rb +9 -0
- data/lib/simple_english/lint/lint_plan.rb +22 -0
- data/lib/simple_english/{markdown.rb → lint/markdown.rb} +28 -10
- data/lib/simple_english/lint/plain_text.rb +30 -0
- data/lib/simple_english/{result.rb → lint/result.rb} +1 -1
- data/lib/simple_english/{config.rb → setup/config.rb} +3 -2
- data/lib/simple_english/setup/fingerprint.rb +38 -0
- data/lib/simple_english/{install.rb → setup/install.rb} +19 -9
- data/lib/simple_english/setup/languagetool.rb +226 -0
- data/lib/simple_english/version.rb +1 -1
- data/lib/simple_english.rb +25 -43
- data/rules/simple-english.xml +5 -1
- metadata +42 -36
- data/lib/simple_english/client.rb +0 -165
- data/lib/simple_english/engine.rb +0 -31
- data/lib/simple_english/finding.rb +0 -8
- data/lib/simple_english/languagetool.rb +0 -143
- data/lib/simple_english/plain_text.rb +0 -18
- /data/lib/simple_english/{annotated_text.rb → lint/annotated_text.rb} +0 -0
- /data/lib/simple_english/{counts.rb → lint/counts.rb} +0 -0
- /data/lib/simple_english/{paragraph.rb → lint/paragraph.rb} +0 -0
- /data/lib/simple_english/{segment.rb → lint/segment.rb} +0 -0
- /data/lib/simple_english/{span.rb → lint/span.rb} +0 -0
- /data/lib/simple_english/{suppressions.rb → lint/suppressions.rb} +0 -0
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# The complete lint engine, daemon-side. Never call SimpleEnglish.lint_text
|
|
4
|
-
# here: that call probes the daemon and recurses into the server.
|
|
5
|
-
|
|
6
|
-
require "json"
|
|
7
|
-
|
|
8
|
-
module SimpleEnglish
|
|
9
|
-
module Engine
|
|
10
|
-
module_function
|
|
11
|
-
|
|
12
|
-
def lint(text, base_url:, language: nil)
|
|
13
|
-
if language
|
|
14
|
-
spans = SimpleEnglish::Extractor.comment_spans(text, language)
|
|
15
|
-
spans.empty? ? [] :
|
|
16
|
-
SimpleEnglish::Client.check(
|
|
17
|
-
SimpleEnglish::AnnotatedText.build(text, spans), base_url: base_url
|
|
18
|
-
)
|
|
19
|
-
else
|
|
20
|
-
stripped = SimpleEnglish::Markdown.strip(text)
|
|
21
|
-
(SimpleEnglish::Counts.check(stripped) +
|
|
22
|
-
SimpleEnglish::Client.check(stripped, base_url: base_url))
|
|
23
|
-
.sort_by { |finding| [finding.line, finding.rule] }
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def lint_json(text, base_url:, language: nil)
|
|
28
|
-
JSON.generate(lint(text, base_url: base_url, language: language).map(&:to_h))
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# The pinned LanguageTool distro: its version, its rules file, and the
|
|
4
|
-
# downloader. Everything that resolves "where it is on this machine and
|
|
5
|
-
# which java runs it" lives in Install. The engine runs as the daemon's
|
|
6
|
-
# inner HTTP server (lib/simple_english/server.rb).
|
|
7
|
-
|
|
8
|
-
module SimpleEnglish
|
|
9
|
-
module LanguageTool
|
|
10
|
-
RULES_FILE = File.expand_path("../../rules/simple-english.xml", __dir__)
|
|
11
|
-
# The only place a LanguageTool version number appears. `se
|
|
12
|
-
# setup` downloads this version, and every jar path derives from it. No
|
|
13
|
-
# env var can point at another one.
|
|
14
|
-
LT_VERSION = "6.6"
|
|
15
|
-
CACHE_DIR_ENV = "SE_CACHE_DIR"
|
|
16
|
-
JAVA_ENV = "SE_JAVA"
|
|
17
|
-
# macOS ships a /usr/bin/java stub that reports no runtime. Homebrew
|
|
18
|
-
# installs the real one here, outside PATH.
|
|
19
|
-
HOMEBREW_JAVA = "/opt/homebrew/opt/openjdk/bin/java"
|
|
20
|
-
TIMEOUT_SECONDS = 300
|
|
21
|
-
|
|
22
|
-
module_function
|
|
23
|
-
|
|
24
|
-
# Download and unpack the pinned LanguageTool into DIR. Idempotent:
|
|
25
|
-
# returns the install directory, or nil after warning why. Pure Ruby
|
|
26
|
-
# throughout: the download uses Net::HTTP and the unpack uses rubyzip,
|
|
27
|
-
# so setup needs no curl or unzip on the machine.
|
|
28
|
-
def install(dir)
|
|
29
|
-
require "fileutils"
|
|
30
|
-
dest = File.join(dir, "LanguageTool-#{LT_VERSION}")
|
|
31
|
-
if File.exist?(File.join(dest, "languagetool-commandline.jar"))
|
|
32
|
-
remove_stale_versions(dir, dest)
|
|
33
|
-
return dest
|
|
34
|
-
end
|
|
35
|
-
zip = File.join(dir, "LanguageTool-#{LT_VERSION}.zip")
|
|
36
|
-
FileUtils.mkdir_p(dir)
|
|
37
|
-
return nil unless download(download_url, zip)
|
|
38
|
-
return nil unless extract(zip, dir)
|
|
39
|
-
File.delete(zip)
|
|
40
|
-
remove_stale_versions(dir, dest)
|
|
41
|
-
dest
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def download_url
|
|
45
|
-
"https://languagetool.org/download/LanguageTool-#{LT_VERSION}.zip"
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
# Streams URL to TO and follows redirects. Warns and returns false
|
|
49
|
-
# on any transport or HTTP failure, so callers never see a stack
|
|
50
|
-
# trace.
|
|
51
|
-
def download(url, to, redirects: 3)
|
|
52
|
-
require "net/http"
|
|
53
|
-
uri = URI(url)
|
|
54
|
-
Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https",
|
|
55
|
-
open_timeout: 10, read_timeout: 60) do |http|
|
|
56
|
-
http.request(Net::HTTP::Get.new(uri)) do |response|
|
|
57
|
-
case response
|
|
58
|
-
when Net::HTTPRedirection
|
|
59
|
-
return false if redirects.zero?
|
|
60
|
-
return download(response["location"], to, redirects: redirects - 1)
|
|
61
|
-
when Net::HTTPSuccess
|
|
62
|
-
File.binwrite(to, "")
|
|
63
|
-
File.open(to, "wb") do |file|
|
|
64
|
-
response.read_body { |chunk| file.write(chunk) }
|
|
65
|
-
end
|
|
66
|
-
return true
|
|
67
|
-
else
|
|
68
|
-
warn "error: download failed: HTTP #{response.code} from #{url}"
|
|
69
|
-
return false
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
rescue SystemCallError, SocketError, Timeout::Error,
|
|
74
|
-
OpenSSL::SSL::SSLError, Net::ProtocolError => e
|
|
75
|
-
warn "error: download failed: #{e.class}: #{e.message}"
|
|
76
|
-
false
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
# Unpacks ZIP into DIR and refuses entries that try to escape it.
|
|
80
|
-
# Warns and returns false on any failure.
|
|
81
|
-
def extract(zip, dir)
|
|
82
|
-
require "zip"
|
|
83
|
-
Zip::File.open(zip) do |archive|
|
|
84
|
-
archive.each do |entry|
|
|
85
|
-
unless safe_entry_target(dir, entry.name)
|
|
86
|
-
warn "error: zip entry escapes the install dir: #{entry.name}"
|
|
87
|
-
return false
|
|
88
|
-
end
|
|
89
|
-
entry.extract(entry.name, destination_directory: dir,
|
|
90
|
-
create_parent_directories: true)
|
|
91
|
-
end
|
|
92
|
-
end
|
|
93
|
-
true
|
|
94
|
-
rescue SystemCallError, Zip::Error => e
|
|
95
|
-
warn "error: unpack failed: #{e.class}: #{e.message}"
|
|
96
|
-
false
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
# The path to write zip entry NAME into, or nil when NAME escapes
|
|
100
|
-
# DIR. A download is untrusted input: this is the zip-slip
|
|
101
|
-
# guard.
|
|
102
|
-
def safe_entry_target(dir, name)
|
|
103
|
-
target = File.expand_path(File.join(dir, name))
|
|
104
|
-
base = File.expand_path(dir) + File::SEPARATOR
|
|
105
|
-
target.start_with?(base) ? target : nil
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
# One gem version pins one LanguageTool version. Older dirs are
|
|
109
|
-
# hundreds of MB each, so delete them on every setup run and keep
|
|
110
|
-
# only the current version (and any zips: they are re-deleted or
|
|
111
|
-
# re-extracted by their own flow).
|
|
112
|
-
def remove_stale_versions(dir, keep)
|
|
113
|
-
require "fileutils"
|
|
114
|
-
Dir.glob(File.join(dir, "LanguageTool-*")).each do |entry|
|
|
115
|
-
FileUtils.rm_rf(entry) if File.directory?(entry) && entry != keep
|
|
116
|
-
end
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
# Proves the installation works end to end: java runs the
|
|
120
|
-
# commandline jar and the custom rules load. The command exits
|
|
121
|
-
# nonzero on a broken java, a corrupt jar, or invalid rules XML,
|
|
122
|
-
# so setup can report a real verdict instead of "files exist".
|
|
123
|
-
# Returns a boolean, never raises or warns: the caller owns the
|
|
124
|
-
# message.
|
|
125
|
-
def smoke(install)
|
|
126
|
-
rule = rule_ids.first
|
|
127
|
-
return false if rule.nil?
|
|
128
|
-
require "tmpdir"
|
|
129
|
-
Dir.mktmpdir do |dir|
|
|
130
|
-
text = File.join(dir, "smoke.txt")
|
|
131
|
-
File.write(text, "Check this sentence.\n")
|
|
132
|
-
system(install.java!, "-jar", install.commandline_jar,
|
|
133
|
-
"--language", "en", "--rulefile", RULES_FILE,
|
|
134
|
-
"--enable", rule, "--enabledonly", text,
|
|
135
|
-
out: File::NULL, err: File::NULL) ? true : false
|
|
136
|
-
end
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
def rule_ids
|
|
140
|
-
File.read(RULES_FILE).scan(/<rule(?:group)? id="(\w+)"/).flatten
|
|
141
|
-
end
|
|
142
|
-
end
|
|
143
|
-
end
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module SimpleEnglish
|
|
4
|
-
module Client
|
|
5
|
-
# The plain-text payload for /v2/check, duck-compatible with
|
|
6
|
-
# AnnotatedText::Result: #lt_params and #locate.
|
|
7
|
-
PlainText = Struct.new(:text) do
|
|
8
|
-
def lt_params
|
|
9
|
-
{"text" => text}
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def locate(utf16_offset)
|
|
13
|
-
[Client.offset_to_line(text, utf16_offset),
|
|
14
|
-
Client.offset_to_column(text, utf16_offset)]
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|