ovec 0.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bf233d8093609535f86f06d12e54d8d53ea44da0
4
+ data.tar.gz: 61af216b5f2b5bda2dafe0affd86d3991ac9b957
5
+ SHA512:
6
+ metadata.gz: ae3384bf00f9d20dd2ab7cc398a70959a44454ed953c1f0ec9cbddb485fc06adeace43e1313baf8fdcea80f1bb7b45fa2459d7ec3437b65f7f981dc384858ddf
7
+ data.tar.gz: 11ffb6b266c098c33047a48962f461de4c602b77e5c9737739157f59816dc00632e12ac81b1a184016ea8b52876ce2e40893e8e809df9ac75455c51acab6643a
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ovec.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Michal Pokorný
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,33 @@
1
+ # Ovec
2
+
3
+ Ovec is a linter for Czech TeX documents inspired by the capabilities of Vlna by Petr Olšák (http://petr.olsak.net/).
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'ovec'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install ovec
18
+
19
+ ## Usage
20
+
21
+ Use the installed binary `ovec` as a filter.
22
+ Right now, it writes out some debug messages to stderr - this will be fixed in a later version.
23
+ Usage example:
24
+
25
+ $ cat input.tex | ovec > output.tex
26
+
27
+ ## Contributing
28
+
29
+ 1. Fork it
30
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
31
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
32
+ 4. Push to the branch (`git push origin my-new-feature`)
33
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'lib/ovec'
6
+ t.test_files = FileList['test/lib/ovec/*.rb']
7
+ t.verbose = true
8
+ end
9
+
10
+ task :default => :test
data/TODO ADDED
@@ -0,0 +1,9 @@
1
+ - vlnky kolem promennych: graf~$X$, promenna~$Y$, ...
2
+ - \, v cislech misto mezery?
3
+ - ,~... (respektive \dots; nechci za tim sezrat mezeru - ???)
4
+ - varovat na ...?
5
+ - uvozovky (bacha na neparove). warn / correct?
6
+ - vlnkovadlo dle Olsaka.
7
+ - pozorovat ovlnkovany zdrojak.
8
+ - nevlnkovat:
9
+ - obecne makra, ve kterych se nevlnkuje
data/bin/ovec ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'ovec'
4
+
5
+ content = ARGF.read
6
+
7
+ parser = Ovec::Parser.new
8
+ tree = parser.parse(content)
9
+
10
+ tm = Ovec::TexManipulator.new
11
+ tm.bind(tree)
12
+
13
+ tier = Ovec::Tier.new
14
+
15
+ tm.run_text_manipulator(tier)
16
+
17
+ puts tree.to_tex
data/lib/ovec/nodes.rb ADDED
@@ -0,0 +1,127 @@
1
+ module Ovec
2
+ class Node
3
+ end
4
+
5
+ class CommentNode < Node
6
+ def initialize(content)
7
+ @content = content
8
+ end
9
+
10
+ def to_tex
11
+ content
12
+ end
13
+
14
+ attr_reader :content
15
+ end
16
+
17
+ class TextCommandsNode < Node
18
+ # If verbatim, do not interpret content as actual text.
19
+ def initialize(command, content, text: true)
20
+ @command = command
21
+ @content = content
22
+ @text = text
23
+ end
24
+
25
+ def to_tex
26
+ "\\#@command{#{@content.to_tex}}"
27
+ end
28
+
29
+ def text?; @text; end
30
+
31
+ attr_reader :command
32
+ attr_reader :content
33
+ end
34
+
35
+ class VerbatimNode < Node
36
+ def initialize(command, delimiter, content)
37
+ @command = command
38
+ @delimiter = delimiter
39
+ @content = content
40
+ end
41
+
42
+ def left_delimiter
43
+ @delimiter
44
+ end
45
+
46
+ def right_delimiter
47
+ Parser.delimiter_right_side @delimiter
48
+ end
49
+
50
+ def to_tex
51
+ "\\#@command#{left_delimiter}#@content#{right_delimiter}"
52
+ end
53
+ end
54
+
55
+ class CommandsNode < Node
56
+ def initialize(content)
57
+ @content = content
58
+ end
59
+
60
+ def to_tex
61
+ "\\#{content}"
62
+ end
63
+
64
+ attr_reader :content
65
+ end
66
+
67
+ class MathNode < Node
68
+ INLINE = :inline
69
+ DISPLAY = :display
70
+
71
+ def initialize(type, content)
72
+ @type = type
73
+ @content = content
74
+ end
75
+
76
+ def to_tex
77
+ if type == INLINE
78
+ "$#{content}$"
79
+ else
80
+ "$$#{content}$$"
81
+ end
82
+ end
83
+
84
+ attr_reader :type
85
+ attr_reader :content
86
+ end
87
+
88
+ class TextNode < Node
89
+ def initialize(text)
90
+ @text = text
91
+ end
92
+
93
+ def length
94
+ text.length
95
+ end
96
+
97
+ def to_tex
98
+ text
99
+ end
100
+
101
+ attr_reader :text
102
+ end
103
+
104
+ class CombinedNode < Node
105
+ def initialize(content = [])
106
+ @content = content
107
+ end
108
+
109
+ def <<(thing)
110
+ @content << thing
111
+ end
112
+
113
+ def to_tex()
114
+ content.map(&:to_tex).join('')
115
+ end
116
+
117
+ def length
118
+ @content.length
119
+ end
120
+
121
+ def [](index)
122
+ @content[index]
123
+ end
124
+
125
+ attr_reader :content
126
+ end
127
+ end
@@ -0,0 +1,169 @@
1
+ module Ovec
2
+ class ParseError < StandardError
3
+ end
4
+
5
+ # TODO: verbatimy; TeX prikazy obsahujici kusy k ovlnkovani
6
+
7
+ class Parser
8
+ NORMAL_REGEX = /\A([^\\$%])+/
9
+ # TODO: more escapes: there are probably 10x more...
10
+ COMMAND_REGEX = /\A\\([a-zA-Z0-9]+|[%:,\\])/
11
+ COMMENT_REGEX = /\A%.*$/
12
+
13
+ TEXT_COMMANDS = %w(textit textbf textsc title author)
14
+ # TODO: seznam prikazu, ve kterych se nevlnkuje
15
+
16
+ NONTEXT_CONTENT_COMMANDS = %w() # TODO: treba \begin, \end, ...
17
+
18
+ VERBATIM_COMMANDS = %w(verbatim verb)
19
+
20
+ private
21
+ def debug(*args)
22
+ $stderr.puts(*args)
23
+ end
24
+
25
+ def find_other_side(string, start, left = '{', right = '}')
26
+ level = 0
27
+ for i in start...string.length
28
+ if string[i] == left && (right != left || i == start)
29
+ level += 1
30
+ elsif string[i] == right
31
+ level -= 1
32
+ end
33
+
34
+ return i if level == 0
35
+ end
36
+
37
+ raise ParseError, "No matching #{right} found for #{left} in #{string} from index #{start}."
38
+ end
39
+
40
+ public
41
+ def self.delimiter_right_side(left)
42
+ {
43
+ '{' => '}', '[' => ']', '(' => ')', '<' => '>'
44
+ }[left] || left
45
+ end
46
+
47
+ def eat_node(code, index)
48
+ to_eat = code[index...code.length]
49
+
50
+ if to_eat.empty?
51
+ raise ParseError, "Parsing an empty string"
52
+ end
53
+
54
+ # Cut off comments
55
+ match = COMMENT_REGEX.match(to_eat)
56
+ unless match.nil?
57
+ match = match[0]
58
+ node = CommentNode.new(match)
59
+
60
+ debug "Eaten #{match.length} chars of comments."
61
+ return node, match.length
62
+ end
63
+
64
+ # Cut off normal text
65
+ match = NORMAL_REGEX.match(to_eat)
66
+ unless match.nil?
67
+ match = match[0]
68
+ node = TextNode.new(match)
69
+
70
+ debug "Eaten #{match.length} chars of normal text."
71
+ return node, match.length
72
+ end
73
+
74
+ # Parse a command. If the command looks like a text-command, try to eat everything between { and }.
75
+ match = COMMAND_REGEX.match(to_eat)
76
+ unless match.nil?
77
+ command = match[1]
78
+ match_len = match[0].length
79
+ debug "Eating command #{command}."
80
+
81
+ if TEXT_COMMANDS.include?(command) || NONTEXT_CONTENT_COMMANDS.include?(command)
82
+ if to_eat.length > match_len && to_eat[match_len] == '{'
83
+ debug "Looks like a text command, trying to parse recursively."
84
+ begin
85
+ other_side = find_other_side(to_eat, match_len, '{', '}')
86
+
87
+ content = parse(code[index + match_len + 1...index + other_side])
88
+ # TODO: rename textcommands to something better: command with params?
89
+ node = TextCommandsNode.new(command, content, text: TEXT_COMMANDS.include?(command))
90
+
91
+ debug "Eaten #{other_side + 1} chars of text command."
92
+ return node, (other_side + 1)
93
+ rescue ParseError
94
+ debug "Parse error encountered. Giving up on this node."
95
+ end
96
+ end
97
+ end
98
+
99
+ if VERBATIM_COMMANDS.include?(command)
100
+ if to_eat.length <= match_len
101
+ raise ParseError, "Verbatim at EOF with no delimiter."
102
+ end
103
+
104
+ left_delimiter = to_eat[match_len]
105
+ right_delimiter = self.class.delimiter_right_side(left_delimiter)
106
+
107
+ # TODO: nesting in verbatims ???
108
+ other_side = find_other_side(to_eat, match_len, left_delimiter, right_delimiter)
109
+
110
+ content = to_eat[match_len + 1...other_side]
111
+
112
+ node = VerbatimNode.new(command, left_delimiter, content)
113
+
114
+ debug "Eaten #{other_side + 1} chars of verbatim."
115
+ return node, (other_side + 1)
116
+ end
117
+
118
+ node = CommandsNode.new(command)
119
+
120
+ debug "Eaten #{match_len} chars of commands."
121
+ return node, match_len
122
+ end
123
+
124
+ if to_eat.length > 1 && to_eat[0..1] == "$$"
125
+ # Lookaround assertion to handle escaped dollars in math.
126
+ ending = to_eat[2...to_eat.length].index(/(?<!\\)\$\$/)
127
+
128
+ if ending.nil?
129
+ raise ParseError, "Unterminated $$ starting at #{index}"
130
+ end
131
+
132
+ node = MathNode.new(MathNode::DISPLAY, to_eat[2...ending+2])
133
+ eaten = ending + 4
134
+ debug "Eaten #{eaten} chars of inline math."
135
+ return node, eaten
136
+ end
137
+
138
+ if to_eat[0] == '$'
139
+ # Lookaround assertion to handle escaped dollars in math.
140
+ ending = to_eat[1...to_eat.length].index(/(?<!\\)\$/)
141
+
142
+ if ending.nil?
143
+ raise ParseError, "Unterminated $ starting at #{index}"
144
+ end
145
+
146
+ node = MathNode.new(MathNode::INLINE, to_eat[1...ending+1])
147
+ eaten = ending + 2
148
+ debug "Eaten #{eaten} chars of inline math."
149
+ return node, eaten
150
+ end
151
+
152
+ raise ParseError, "Don't know how to parse '#{to_eat}'."
153
+ end
154
+
155
+ def parse(code)
156
+ result = CombinedNode.new
157
+
158
+ index = 0
159
+ while index < code.length
160
+ node, shift = eat_node(code, index)
161
+ index += shift
162
+
163
+ result << node
164
+ end
165
+
166
+ return result
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,29 @@
1
+ module Ovec
2
+ class TexManipulator
3
+ def bind(root)
4
+ @root = root
5
+ end
6
+
7
+ private
8
+ def load_text_chunks_dfs(node)
9
+ case node
10
+ when Ovec::TextCommandsNode then
11
+ load_text_chunks_dfs(node.content) if node.text?
12
+ when Ovec::TextNode then
13
+ @text_chunks << node.text
14
+ when Ovec::CombinedNode then
15
+ node.content.each { |subnode|
16
+ load_text_chunks_dfs(subnode)
17
+ }
18
+ end
19
+ end
20
+
21
+ public
22
+ def run_text_manipulator(manipulator)
23
+ @text_chunks = []
24
+ load_text_chunks_dfs(@root)
25
+ manipulator.bind(@text_chunks)
26
+ manipulator.run
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,33 @@
1
+ module Ovec
2
+ class TextManipulator
3
+ # Subclasses, note: once you change the length of a chunk, delimiters will no longer be correct.
4
+
5
+ def bind(chunks)
6
+ @chunks = chunks
7
+ @delimiters = [0]
8
+ chunks.each do |chunk|
9
+ @delimiters << @delimiters.last + chunk.length
10
+ end
11
+
12
+ _rejoin
13
+ end
14
+
15
+ protected
16
+
17
+ # Given an offset in the original string, returns the chunk and chunk offset
18
+ # that contains the refers to the same character.
19
+ def _find_chunk_and_offset(offset)
20
+ j = 0
21
+ while j < @delimiters.size - 1
22
+ break if @delimiters[j + 1] > offset
23
+ j += 1
24
+ end
25
+
26
+ return [ @chunks[j], offset - @delimiters[j] ]
27
+ end
28
+
29
+ def _rejoin
30
+ @joined = @chunks.join('')
31
+ end
32
+ end
33
+ end
data/lib/ovec/tier.rb ADDED
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/ruby -w
2
+
3
+ module Ovec
4
+ class Tier < TextManipulator
5
+ # The last character this regex matches is changed to a tilde.
6
+ REGEX = /(
7
+ ((\p{Z}|\~|\n)[KkSsVvZzOoUu]\p{Z})| # KSVZOU jako samostatne slovo
8
+ ([\.\?\!](\p{Z}|\~)+[KSVZOUAI]\p{Z})| # KSVZOUAI na zacatku vety
9
+ (\A[KSVZOUAI]\p{Z})| # KSVZOUAI na zacatku textu
10
+ (\p{Z}(?=--(\p{Z}|\n)))| # mezera, za kterou je pomlcka
11
+ (,(\p{Z}|\~|\n)+a\p{Z}) # ... modulo 10, a~timto prvkem ...; TODO: plati tohle i pro "i"?
12
+ )/x
13
+
14
+ # TODO: generally tie "5.~batalion", ...
15
+ # All changes within this regex are changed to a tilde.
16
+ DATE_REGEX = /(
17
+ (?<=\p{Z})\p{Nd}{1,2}\.\p{Z}
18
+ (\p{Nd}{1,2}\.|leden|únor|březen|duben|květen|červen|červenec|srpen|září|říjen|listopad|prosinec| # TODO: plne sklonovani? nebo nejaky wildcard?
19
+ ledna|února|března|dubna|května|června|července|srpna|září|října|listopadu|prosince)\p{Z}
20
+ \p{Nd}{4}(?=\p{Z}) # Datum jako "1. 5. 2013"
21
+ )/x
22
+
23
+ def run
24
+ # ~ neni mezi \p{Z}.
25
+ # TODO: moznosti na dvojpismenne predlozky
26
+ matches = @joined.to_enum(:scan, REGEX).map { Regexp.last_match }
27
+
28
+ # Matches may overlap, find all matches with more scans.
29
+ # TODO: optimize
30
+ until matches.empty?
31
+ for i in 0...matches.length
32
+ # TODO: check ze za tim neni tilda nikde (napr. na dalsim radku, par mezer pozdeji, ...)
33
+ match = matches[i]
34
+ change = match.end(0) - 1
35
+ chunk, offset = _find_chunk_and_offset(change)
36
+ chunk[offset] = '~'
37
+ end
38
+
39
+ _rejoin
40
+ matches = @joined.to_enum(:scan, REGEX).map { Regexp.last_match }
41
+ end
42
+
43
+ # Dates can't overlap. 1 scan is enough.
44
+ matches = @joined.to_enum(:scan, DATE_REGEX).map { Regexp.last_match }
45
+ for i in 0...matches.length
46
+ match = matches[i]
47
+ for j in match.begin...match.end
48
+ if @joined[j] == ' '
49
+ chunk, offset = _find_chunk_and_offset(j)
50
+ chunk[offset] = '~'
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,3 @@
1
+ module Ovec
2
+ VERSION = "0.0.2"
3
+ end
data/lib/ovec.rb ADDED
@@ -0,0 +1,9 @@
1
+ require "ovec/version"
2
+ require "ovec/nodes"
3
+ require "ovec/parser"
4
+ require "ovec/tex_manipulator"
5
+ require "ovec/text_manipulator"
6
+ require "ovec/tier"
7
+
8
+ module Ovec
9
+ end
data/ovec.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ovec/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ovec"
8
+ spec.version = Ovec::VERSION
9
+ spec.authors = ["Michal Pokorný"]
10
+ spec.email = ["pok@rny.cz"]
11
+ spec.description = %q{A TeX linter for the Czech language.}
12
+ spec.summary = %q{Ovec inserts nonbreakable spaces into your Czech language TeX files.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+
24
+ spec.required_ruby_version = ">= 2"
25
+ end
@@ -0,0 +1,77 @@
1
+ require_relative '../../test_helper'
2
+
3
+ module Ovec
4
+ class ParserTest < Test::Unit::TestCase
5
+ def setup
6
+ @parser = Parser.new
7
+ end
8
+
9
+ def test_basic_text_parsing
10
+ text = "Hello world!"
11
+ node, eaten = @parser.eat_node(text, 0)
12
+ assert_equal text.length, eaten
13
+ assert node.is_a?(TextNode)
14
+ assert_equal text.length, node.length
15
+ end
16
+
17
+ def test_basic_math_parsing
18
+ text = "$10+5=7$"
19
+ node, eaten = @parser.eat_node(text, 0)
20
+ assert_equal text.length, eaten
21
+ assert node.is_a?(MathNode)
22
+ assert_equal node.type, MathNode::INLINE
23
+ assert_equal node.content, text[1...(text.length - 1)]
24
+ end
25
+
26
+ def test_basic_display_math_parsing
27
+ text = "$$10+5=7$$"
28
+ node, eaten = @parser.eat_node(text, 0)
29
+ assert_equal text.length, eaten
30
+ assert node.is_a?(MathNode)
31
+ assert_equal node.type, MathNode::DISPLAY
32
+ assert_equal node.content, text[2...(text.length - 2)]
33
+ end
34
+
35
+ def test_basic_composite_parsing
36
+ text = "Ahoj světe. $10 + 5 = 3$\n\n\tSbohem. $$X \geq 4$$"
37
+ result = @parser.parse(text)
38
+ assert result.is_a?(CombinedNode)
39
+ assert_equal text, result.to_tex
40
+ end
41
+
42
+ def test_escaped_dollar_math
43
+ input = "$$Ahoj\\$$Svete$$"
44
+ result = @parser.parse(input)
45
+ assert result.length == 1
46
+ assert result[0].is_a? MathNode
47
+ assert result[0].content == "Ahoj\\$$Svete"
48
+ end
49
+
50
+ def test_text_command_parsing
51
+ text = '\textbf{Ahoj. Tohle je \textit{text}, ktery se bude vlnkovat.}'
52
+ result = @parser.parse(text)
53
+ assert result.is_a?(CombinedNode)
54
+ assert result.length == 1
55
+
56
+ node = result[0]
57
+ assert node.is_a?(TextCommandsNode)
58
+ assert node.command == "textbf"
59
+
60
+ node2 = node.content
61
+ assert node2.is_a?(CombinedNode)
62
+ assert node2.length == 3
63
+ assert node2[0].is_a?(TextNode)
64
+ assert node2[0].text == "Ahoj. Tohle je "
65
+ assert node2[1].is_a?(TextCommandsNode)
66
+ assert node2[1].command == "textit"
67
+ assert node2[1].content[0].text == "text"
68
+ assert node2[2].text == ", ktery se bude vlnkovat."
69
+ end
70
+
71
+ def test_command_parsed
72
+ text = '\blabla'
73
+ result = @parser.parse(text)
74
+ assert_equal text, result.to_tex
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,39 @@
1
+ require_relative '../../test_helper'
2
+
3
+ module Ovec
4
+ class TexManipulatorTest < Test::Unit::TestCase
5
+ def setup
6
+ @tm = TexManipulator.new
7
+ @tier = Tier.new
8
+ @parser = Parser.new
9
+ end
10
+
11
+ def test_commands_reversible
12
+ tex = '\heading{Ahoj}'
13
+ tree = @parser.parse(tex)
14
+ assert_equal tex, tree.to_tex
15
+ end
16
+
17
+ private
18
+ def assert_ties_to(input, output)
19
+ tree = @parser.parse(input)
20
+ assert tree.is_a?(CombinedNode)
21
+ @tm.bind(tree)
22
+ @tm.run_text_manipulator(@tier)
23
+ assert_equal output, tree.to_tex
24
+ end
25
+
26
+ public
27
+ def test_basic_tex
28
+ input = 'Ahoj svete. \\textbf{I v ceskych luzich dochazi k ubytku s\\textit{ prichodem} podzimu.}'
29
+ output = 'Ahoj svete. \\textbf{I~v~ceskych luzich dochazi k~ubytku s\\textit{~prichodem} podzimu.}'
30
+ assert_ties_to input, output
31
+ end
32
+
33
+ def test_with_verb
34
+ input = 'Ahoj. \verb|Tohle % je ve verbatimu, takze to neni komentar. V tomhle se nevlnkuje.| V tomhle kusu se uz zase vlnkuje.'
35
+ output = 'Ahoj. \verb|Tohle % je ve verbatimu, takze to neni komentar. V tomhle se nevlnkuje.| V~tomhle kusu se uz zase vlnkuje.'
36
+ assert_ties_to input, output
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,65 @@
1
+ require_relative '../../test_helper'
2
+
3
+ module Ovec
4
+ class TierTest < Test::Unit::TestCase
5
+ def setup
6
+ @tier = Tier.new
7
+ end
8
+
9
+ def test_basic_without_ties
10
+ text = "Ahoj. Jak se máš?"
11
+ text_duplicate = text.dup
12
+ @tier.bind([text_duplicate])
13
+ @tier.run
14
+ assert_equal text, text_duplicate
15
+ end
16
+
17
+ private
18
+ def assert_ties_to(input, output)
19
+ input = [input] if input.is_a? String
20
+ output = [output] if output.is_a? String
21
+ text = input.dup
22
+ @tier.bind(test)
23
+ @tier.run
24
+ assert_equal text, outpu
25
+ end
26
+
27
+ def test_simple_tie
28
+ assert_ties_to "K blabla u blabla s blabla.", "K~blabla u~blabla s~blabla."
29
+ end
30
+
31
+ def test_array_tie
32
+ assert_ties_to [ "K blabla u", " blabla ", "s blabla.", " A blabla?" ], [ "K~blabla u", "~blabla ", "s~blabla.", " A~blabla?" ]
33
+ end
34
+
35
+ def test_regex_works
36
+ regex = Tier::REGEX
37
+ assert !("ahoj" =~ regex)
38
+ assert "~v " =~ regex
39
+ assert "Cau. A hrdy bud, zes vytrval." =~ regex
40
+ end
41
+
42
+ def test_hard_tie
43
+ assert_ties_to "I v ceskych luzich dochazi k ubytku s prichodem podzimu.",
44
+ "I~v~ceskych luzich dochazi k~ubytku s~prichodem podzimu."
45
+ end
46
+
47
+ def test_tie_dash
48
+ assert_ties_to "Ach -- pomlcka!", "Ach~-- pomlcka!"
49
+ assert_ties_to "Ach --\npomlcka!", "Ach~--\npomlcka!"
50
+ end
51
+
52
+ def test_tie_across_newline
53
+ assert_ties_to "Pojednani pojednavajici\no pojednavani.", "Pojednavani pojednavajici\no~pojednavani."
54
+ end
55
+
56
+ def test_tie_a_after_pause
57
+ assert_ties_to "Kone se pasou, a ovce se pasou.", "Kone se pasou, a~ovce se pasou."
58
+ end
59
+
60
+ def test_tie_date
61
+ assert_ties_to "3. 4. 2012", "3.~4.~2012"
62
+ assert_ties_to "1. leden 1950", "1.~leden~1950"
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,2 @@
1
+ require 'test/unit'
2
+ require 'ovec'
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ovec
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Michal Pokorný
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-05-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: A TeX linter for the Czech language.
42
+ email:
43
+ - pok@rny.cz
44
+ executables:
45
+ - ovec
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - .gitignore
50
+ - Gemfile
51
+ - LICENSE.txt
52
+ - README.md
53
+ - Rakefile
54
+ - TODO
55
+ - bin/ovec
56
+ - lib/ovec.rb
57
+ - lib/ovec/nodes.rb
58
+ - lib/ovec/parser.rb
59
+ - lib/ovec/tex_manipulator.rb
60
+ - lib/ovec/text_manipulator.rb
61
+ - lib/ovec/tier.rb
62
+ - lib/ovec/version.rb
63
+ - ovec.gemspec
64
+ - test/lib/ovec/parser.rb
65
+ - test/lib/ovec/tex_manipulator.rb
66
+ - test/lib/ovec/tier.rb
67
+ - test/test_helper.rb
68
+ homepage: ''
69
+ licenses:
70
+ - MIT
71
+ metadata: {}
72
+ post_install_message:
73
+ rdoc_options: []
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '2'
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ requirements: []
87
+ rubyforge_project:
88
+ rubygems_version: 2.0.0
89
+ signing_key:
90
+ specification_version: 4
91
+ summary: Ovec inserts nonbreakable spaces into your Czech language TeX files.
92
+ test_files:
93
+ - test/lib/ovec/parser.rb
94
+ - test/lib/ovec/tex_manipulator.rb
95
+ - test/lib/ovec/tier.rb
96
+ - test/test_helper.rb