hierogloss 0.0.1
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 +7 -0
- data/.gitignore +19 -0
- data/.travis.yml +3 -0
- data/GARDINER-LICENSE.txt +6 -0
- data/Gemfile +4 -0
- data/KRAMDOWN-LICENSE.txt +29 -0
- data/LICENSE.txt +15 -0
- data/README.md +72 -0
- data/Rakefile +8 -0
- data/UNICODE-DATA-LICENSE.txt +15 -0
- data/UNLICENSE.txt +30 -0
- data/assets/fonts/Gardiner.eot +0 -0
- data/assets/fonts/Gardiner.otf +0 -0
- data/assets/fonts/Gardiner.svg +13593 -0
- data/assets/fonts/Gardiner.ttf +0 -0
- data/assets/fonts/Gardiner.woff +0 -0
- data/bin/hierogloss +25 -0
- data/data/Unicode-MdC-Mapping-v1.utf8 +1001 -0
- data/data/hierogloss.html.erb +55 -0
- data/examples/disjunction.md +13 -0
- data/examples/disjunction.png +0 -0
- data/examples/liverpool.md +11 -0
- data/hierogloss.gemspec +26 -0
- data/lib/hierogloss/dictionary.rb +39 -0
- data/lib/hierogloss/gloss.rb +174 -0
- data/lib/hierogloss/version.rb +3 -0
- data/lib/hierogloss.rb +24 -0
- data/lib/kramdown/converter/bbcode.rb +113 -0
- data/lib/kramdown/converter/htlal.rb +34 -0
- data/lib/kramdown/parser/hierogloss.rb +37 -0
- data/src/Gardiner.ttf +0 -0
- data/test/minitest_helper.rb +4 -0
- data/test/test_dictionary.rb +50 -0
- data/test/test_gloss.rb +43 -0
- data/test/test_hierogloss.rb +7 -0
- data/test/test_kramdown_extensions.rb +72 -0
- metadata +157 -0
@@ -0,0 +1,55 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<%
|
6
|
+
# This code from Kramdown's default template.
|
7
|
+
extend ::Kramdown::Utils::Html
|
8
|
+
title = 'Hierogloss'
|
9
|
+
h = @converter.root.children.find {|c| c.type == :header}
|
10
|
+
if h
|
11
|
+
collector = lambda {|c| c.children.collect {|cc| cc.type == :text ? escape_html(cc.value, :text) : collector.call(cc)}.join('')}
|
12
|
+
title = collector.call(h)
|
13
|
+
end
|
14
|
+
%>
|
15
|
+
<title><%= title %></title>
|
16
|
+
<meta name="generator" content="hierogloss kramdown <%= ::Kramdown::VERSION %>" />
|
17
|
+
|
18
|
+
<style type="text/css">
|
19
|
+
@font-face {
|
20
|
+
font-family: 'WebGardiner';
|
21
|
+
src: url('fonts/Gardiner.eot');
|
22
|
+
src: local('βΊ'), url('fonts/Gardiner.woff') format('woff'), url('fonts/Gardiner.ttf') format('truetype'), url('fonts/Gardiner.svg') format('svg');
|
23
|
+
font-weight: normal;
|
24
|
+
font-style: normal;
|
25
|
+
}
|
26
|
+
|
27
|
+
.hgls-h, .hgls-l {
|
28
|
+
font-family: "WebGardiner", "Aegyptus", "Gardiner", serif;
|
29
|
+
}
|
30
|
+
.hgls-l { font-style: normal; font-size: 18pt; }
|
31
|
+
.hgls-h { font-size: 24px; }
|
32
|
+
|
33
|
+
.hgls-gloss td { padding-right: 18px; }
|
34
|
+
.hgls-gloss {
|
35
|
+
margin-left: 18px;
|
36
|
+
page-break-inside: avoid;
|
37
|
+
}
|
38
|
+
p.hgls-gloss {
|
39
|
+
margin-top: 0;
|
40
|
+
}
|
41
|
+
table.hgls-gloss a:link, table.hgls-gloss a:visited {
|
42
|
+
color: black;
|
43
|
+
text-decoration: none;
|
44
|
+
}
|
45
|
+
table.hgls-gloss a:hover {
|
46
|
+
text-decoration: underline;
|
47
|
+
}
|
48
|
+
</style>
|
49
|
+
</head>
|
50
|
+
<body>
|
51
|
+
|
52
|
+
<%= @body %>
|
53
|
+
|
54
|
+
</body>
|
55
|
+
</html>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# Disjunction in Middle Egyptian
|
2
|
+
|
3
|
+
This example is based on one in Allen's excellent [Middle Egyptian: An
|
4
|
+
Introduction to the Language and Culture of Hieroglyphs][allen].
|
5
|
+
|
6
|
+
H: πππ€ | πππ | ππ€πͺπ
±
|
7
|
+
L: s | s.t | r-pw
|
8
|
+
G: man | woman | whichever
|
9
|
+
T: either [a] man or [a] woman
|
10
|
+
|
11
|
+
You can emphasize an "or" by following the options with {r-pw}.
|
12
|
+
|
13
|
+
[allen]: http://www.amazon.com/Middle-Egyptian-Introduction-Language-Hieroglyphs/dp/0521741440
|
Binary file
|
@@ -0,0 +1,11 @@
|
|
1
|
+
H: π | π ππΏπ
±π΅ππͺ | πΉπ | πππ
|
2
|
+
L: wab | mnTw-Htp | ir(w)~n | Hnw.t
|
3
|
+
G: prΓͺtre | Mentouhotep | nΓ© de | Henout
|
4
|
+
|
5
|
+
H: π | ππππ΄πππ
± | ππ»
|
6
|
+
L: wab | rnfsnbw | mAa(-xrw)
|
7
|
+
G: prΓͺtre | Renef-senebou | juste de voix
|
8
|
+
|
9
|
+
H: π
ππ | πππ | πΉπ | πππ₯πππ | ππ»
|
10
|
+
L: sA.t=f | Hnw.t | ir(w) n | nbw(.t)-aat | mAa(.t-xrw)
|
11
|
+
G: fille=sa | Henout | nΓ©e de | Neboutaat | juste de voix
|
data/hierogloss.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'hierogloss/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "hierogloss"
|
8
|
+
spec.version = Hierogloss::VERSION
|
9
|
+
spec.authors = ["Eric Kidd"]
|
10
|
+
spec.email = ["git@randomhacks.net"]
|
11
|
+
spec.description = %q{Extends the Markdown parser Kramdown to support hieroglyphs, inline multi-column glosses, and output to BBCode for use on forums. Includes an executable for processing files and a webfont version of the Gardiner signs.}
|
12
|
+
spec.summary = %q{Markdown extensions for hieroglyphic glosses and BBCode}
|
13
|
+
spec.homepage = "https://github.com/emk/hierogloss"
|
14
|
+
spec.license = "Public domain + other open source licenses"
|
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_dependency "kramdown", "~> 1.3"
|
22
|
+
spec.add_development_dependency "prawn", "~> 0.14.0"
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
spec.add_development_dependency "minitest"
|
26
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
module Hierogloss
|
4
|
+
#:nodoc: Internal dictionary-related utilities. APIs are not stable.
|
5
|
+
module Dictionary
|
6
|
+
DATA_DIR = File.join(File.dirname(__FILE__), '..', '..', 'data')
|
7
|
+
MDC_MAPPING_PATH = File.join(DATA_DIR, "Unicode-MdC-Mapping-v1.utf8")
|
8
|
+
|
9
|
+
GARDINER = {}
|
10
|
+
File.open(MDC_MAPPING_PATH, "r:bom|utf-8") do |f|
|
11
|
+
f.each_line do |l|
|
12
|
+
l.chomp!
|
13
|
+
sign, hex, codes, remarks = l.split(/\t/, 4)
|
14
|
+
for code in codes.split(/ /)
|
15
|
+
next unless code =~ /\A[A-Z][0-9]+\z/
|
16
|
+
GARDINER[sign] = code
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
"πΏππππ
±π²ππͺππ
ππππππ‘ππ΄πππ‘πΌππΏπ§π".each_char do |c|
|
21
|
+
GARDINER.delete(c)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Try to kick things into shape for hierogl.ch.
|
25
|
+
def self.headword(word)
|
26
|
+
hw = word
|
27
|
+
hw.gsub!(/[()]/, '')
|
28
|
+
hw.sub!(/=.*\z/, '')
|
29
|
+
hw.sub!(/\.w?t\z/, 't')
|
30
|
+
hw.sub!(/\..*\z/, '')
|
31
|
+
hw
|
32
|
+
end
|
33
|
+
|
34
|
+
# Given a Unicode hieroglyph, get the corresponding Gardiner sign.
|
35
|
+
def self.gardiner(sign)
|
36
|
+
GARDINER[sign]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
|
4
|
+
require 'hierogloss/dictionary'
|
5
|
+
|
6
|
+
module Hierogloss
|
7
|
+
#:nodoc:
|
8
|
+
class Row
|
9
|
+
attr_reader :raw_cells
|
10
|
+
|
11
|
+
def initialize(row_text)
|
12
|
+
@raw_cells = row_text.split(/\|/).map {|c| c.strip }
|
13
|
+
end
|
14
|
+
|
15
|
+
def span?
|
16
|
+
false
|
17
|
+
end
|
18
|
+
|
19
|
+
def attributes
|
20
|
+
attrs = {}
|
21
|
+
attrs['class'] = class_attr if class_attr
|
22
|
+
attrs
|
23
|
+
end
|
24
|
+
|
25
|
+
def class_attr
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_kramdown
|
30
|
+
attrs = attributes
|
31
|
+
tr = Kramdown::Element.new(:tr, nil, attrs)
|
32
|
+
raw_cells.each do |c|
|
33
|
+
td = Kramdown::Element.new(:td)
|
34
|
+
children = cell_to_kramdown(c)
|
35
|
+
if children.kind_of?(Array)
|
36
|
+
td.children.concat(children)
|
37
|
+
else
|
38
|
+
td.children << children
|
39
|
+
end
|
40
|
+
tr.children << td
|
41
|
+
end
|
42
|
+
tr
|
43
|
+
end
|
44
|
+
|
45
|
+
def cell_to_kramdown(cell)
|
46
|
+
Kramdown::Element.new(:text, cell)
|
47
|
+
end
|
48
|
+
|
49
|
+
def search_link(query, text)
|
50
|
+
base_url = "http://www.hierogl.ch/hiero/Sp%C3%A9cial:Recherche"
|
51
|
+
escaped_query = CGI.escape(query)
|
52
|
+
url = "#{base_url}?search=#{escaped_query}&go=Lire"
|
53
|
+
|
54
|
+
link = Kramdown::Element.new(:a, nil, {'href' => url})
|
55
|
+
link.children << Kramdown::Element.new(:text, text)
|
56
|
+
link
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
#:nodoc:
|
61
|
+
class HieroglyphRow < Row
|
62
|
+
def class_attr
|
63
|
+
'hgls-h'
|
64
|
+
end
|
65
|
+
|
66
|
+
def cell_to_kramdown(cell)
|
67
|
+
cell.chars.map do |c|
|
68
|
+
gardiner = Dictionary.gardiner(c)
|
69
|
+
if !gardiner.nil?
|
70
|
+
search_link("Signe:#{gardiner}", c)
|
71
|
+
else
|
72
|
+
Kramdown::Element.new(:text, c)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
#:nodoc:
|
79
|
+
class TransliterationRow < Row
|
80
|
+
JR_TRANSLITERATION = {
|
81
|
+
"A" => "κ£",
|
82
|
+
"i" => "j",
|
83
|
+
"a" => "κ₯",
|
84
|
+
"H" => "αΈ₯",
|
85
|
+
"x" => "αΈ«",
|
86
|
+
"X" => "αΊ",
|
87
|
+
"S" => "Ε‘",
|
88
|
+
"q" => "αΈ³",
|
89
|
+
"K" => "αΈ³",
|
90
|
+
"T" => "αΉ―",
|
91
|
+
"D" => "αΈ"
|
92
|
+
}
|
93
|
+
|
94
|
+
def self.fancy(tl)
|
95
|
+
tl.chars.map {|c| JR_TRANSLITERATION[c] || c }.join
|
96
|
+
end
|
97
|
+
|
98
|
+
def class_attr
|
99
|
+
'hgls-l'
|
100
|
+
end
|
101
|
+
|
102
|
+
def cell_to_kramdown(cell)
|
103
|
+
fancy = self.class.fancy(cell)
|
104
|
+
search_link(Dictionary.headword(cell), fancy)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
#:nodoc:
|
109
|
+
class TranslationRow
|
110
|
+
attr_reader :text
|
111
|
+
|
112
|
+
def initialize(row_text)
|
113
|
+
@text = row_text.strip
|
114
|
+
end
|
115
|
+
|
116
|
+
def span?
|
117
|
+
true
|
118
|
+
end
|
119
|
+
|
120
|
+
def class_attr
|
121
|
+
'hgls-t'
|
122
|
+
end
|
123
|
+
|
124
|
+
def to_kramdown
|
125
|
+
em = Kramdown::Element.new(:em, nil)
|
126
|
+
em.children << Kramdown::Element.new(:text, text)
|
127
|
+
em
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
#:nodoc:
|
132
|
+
class Gloss
|
133
|
+
attr_reader :rows
|
134
|
+
|
135
|
+
def initialize(text)
|
136
|
+
@rows = text.lines.map {|l| l.chomp }.map do |row|
|
137
|
+
row =~ /\A(\w+):(.*)\z/
|
138
|
+
raise "C'est quoi, [[#{row}]]\?" unless $1 && $2
|
139
|
+
type =
|
140
|
+
case $1
|
141
|
+
when "H" then HieroglyphRow
|
142
|
+
when "L" then TransliterationRow
|
143
|
+
when "T" then TranslationRow
|
144
|
+
else Row
|
145
|
+
end
|
146
|
+
type.new($2)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def to_kramdown
|
151
|
+
result = []
|
152
|
+
# Neither Kramdown nor BBCode support rowspans, so we'll just cheat
|
153
|
+
# for now.
|
154
|
+
rows.chunk {|r| r.span? }.each do |spans, rows|
|
155
|
+
if spans
|
156
|
+
rows.each do |r|
|
157
|
+
class_attr = "hgls-gloss #{r.class_attr}"
|
158
|
+
p = Kramdown::Element.new(:p, nil, 'class' => class_attr)
|
159
|
+
p.children << r.to_kramdown
|
160
|
+
result << p
|
161
|
+
end
|
162
|
+
else
|
163
|
+
table = Kramdown::Element.new(:table, nil, { 'class' => 'hgls-gloss' },
|
164
|
+
alignment: [])
|
165
|
+
tbody = Kramdown::Element.new(:tbody)
|
166
|
+
table.children << tbody
|
167
|
+
rows.each {|r| tbody.children << r.to_kramdown }
|
168
|
+
result << table
|
169
|
+
end
|
170
|
+
end
|
171
|
+
result
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
data/lib/hierogloss.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'kramdown'
|
2
|
+
require "hierogloss/version"
|
3
|
+
require "hierogloss/dictionary"
|
4
|
+
require "hierogloss/gloss"
|
5
|
+
require "kramdown/parser/hierogloss"
|
6
|
+
require "kramdown/converter/bbcode"
|
7
|
+
# No guarantess of backwards compatibility for this one.
|
8
|
+
require "kramdown/converter/htlal"
|
9
|
+
|
10
|
+
# Most of our internal APIs are undocumented at this point, but you
|
11
|
+
# can use this gem via Kramdown's APIs.
|
12
|
+
#
|
13
|
+
# Kramdown::Document.new(ARGF.read, input: 'hierogloss').to_html
|
14
|
+
#
|
15
|
+
# Or if you want to post on an online forum, try:
|
16
|
+
#
|
17
|
+
# Kramdown::Document.new(ARGF.read, input: 'hierogloss').to_bbcode
|
18
|
+
#
|
19
|
+
# Note that the BBCode converter does not yet support all available
|
20
|
+
# Markdown constructs. You're welcome to try other kramdown backends;
|
21
|
+
# some of them may more-or-less work.
|
22
|
+
module Hierogloss
|
23
|
+
# Nothing to do here yet.
|
24
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module Kramdown
|
2
|
+
module Converter
|
3
|
+
# Outputs some of the most common Markdown elements as BBCode.
|
4
|
+
# Everything in this class is internal.
|
5
|
+
class Bbcode < Base
|
6
|
+
include ::Kramdown::Utils::Html
|
7
|
+
|
8
|
+
DISPATCHER = Hash.new {|h,k| h[k] = "convert_#{k}"} #:nodoc:
|
9
|
+
|
10
|
+
def initialize(root, options)
|
11
|
+
super
|
12
|
+
@stack = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def convert(el, opts = {})
|
16
|
+
send(DISPATCHER[el.type], el, opts)
|
17
|
+
end
|
18
|
+
|
19
|
+
def inner(el, opts)
|
20
|
+
@stack.push([el, opts])
|
21
|
+
result = el.children.map do |inner_el|
|
22
|
+
convert(inner_el, options)
|
23
|
+
end
|
24
|
+
@stack.pop
|
25
|
+
result
|
26
|
+
end
|
27
|
+
|
28
|
+
def convert_header(el, opts)
|
29
|
+
tag("b", nil, inner(el, opts)) + ["\n"]
|
30
|
+
end
|
31
|
+
|
32
|
+
def convert_p(el, opts)
|
33
|
+
inner(el, opts) + ["\n"]
|
34
|
+
end
|
35
|
+
|
36
|
+
def convert_blank(el, opts)
|
37
|
+
"\n"
|
38
|
+
end
|
39
|
+
|
40
|
+
def convert_text(el, opts)
|
41
|
+
# Wouldn't it be nice if we could escape BBCode?
|
42
|
+
el.value.gsub(/\s+/, ' ') # Ignore newlines in raw text.
|
43
|
+
end
|
44
|
+
|
45
|
+
def convert_em(el, opts)
|
46
|
+
tag("i", nil, inner(el, opts))
|
47
|
+
end
|
48
|
+
|
49
|
+
def convert_strong(el, opts)
|
50
|
+
tag("b", nil, inner(el, opts))
|
51
|
+
end
|
52
|
+
|
53
|
+
def convert_a(el, opts)
|
54
|
+
tag("url", el.attr['href'], inner(el, opts))
|
55
|
+
end
|
56
|
+
|
57
|
+
def convert_smart_quote(el, opts)
|
58
|
+
entity_to_str(smart_quote_entity(el))
|
59
|
+
end
|
60
|
+
|
61
|
+
def convert_table(el, opts)
|
62
|
+
tag("table", nil, ["\n"] + inner(el, opts))
|
63
|
+
end
|
64
|
+
|
65
|
+
def convert_tbody(el, opts)
|
66
|
+
inner(el, opts)
|
67
|
+
end
|
68
|
+
|
69
|
+
def convert_tr(el, opts)
|
70
|
+
tag("tr", nil, inner(el, opts)) + ["\n"]
|
71
|
+
end
|
72
|
+
|
73
|
+
def convert_td(el, opts)
|
74
|
+
if @stack.last.first.attr['class'] == 'hgls-h'
|
75
|
+
tag("td", nil, tag("size", "24", inner(el, opts)))
|
76
|
+
else
|
77
|
+
tag("td", nil, inner(el, opts))
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def convert_blockquote(el, opts)
|
82
|
+
# No newline because BBCode will add one itself. We also run
|
83
|
+
# results_to_text so we can clean up trailing newlines.
|
84
|
+
tag("quote", nil, results_to_text(inner(el, opts)))
|
85
|
+
end
|
86
|
+
|
87
|
+
def convert_codeblock(el, opts)
|
88
|
+
# No newline because BBCode will add one itself.
|
89
|
+
tag("code", nil, el.value.sub(/\n\z/, ''))
|
90
|
+
end
|
91
|
+
|
92
|
+
def convert_img(el, opts)
|
93
|
+
tag("img", nil, el.attr['src'])
|
94
|
+
end
|
95
|
+
|
96
|
+
def convert_root(el, opts)
|
97
|
+
results_to_text(inner(el, opts))
|
98
|
+
end
|
99
|
+
|
100
|
+
def tag(name, arg, content)
|
101
|
+
if arg
|
102
|
+
["[#{name}=#{arg}]", content, "[/#{name}]"]
|
103
|
+
else
|
104
|
+
["[#{name}]", content, "[/#{name}]"]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def results_to_text(results)
|
109
|
+
results.flatten.compact.join.sub(/\n+\z/, '')
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Kramdown
|
2
|
+
module Converter
|
3
|
+
# Outputs some of the most common Markdown elements in a stripped down
|
4
|
+
# BBCode dialect without table support or reliable font size control.
|
5
|
+
# Everything in this class is internal.
|
6
|
+
class Htlal < Bbcode
|
7
|
+
include ::Kramdown::Utils::Html
|
8
|
+
|
9
|
+
def convert_table(el, opts)
|
10
|
+
inner(el, opts)
|
11
|
+
end
|
12
|
+
|
13
|
+
def convert_tbody(el, opts)
|
14
|
+
inner(el, opts)
|
15
|
+
end
|
16
|
+
|
17
|
+
def convert_tr(el, opts)
|
18
|
+
spaced = []
|
19
|
+
inner(el, opts).each do |td|
|
20
|
+
spaced << td << " | "
|
21
|
+
end
|
22
|
+
spaced.pop
|
23
|
+
spaced << "\n"
|
24
|
+
spaced
|
25
|
+
end
|
26
|
+
|
27
|
+
def convert_td(el, opts)
|
28
|
+
# We'd like to make hieroglyph cells bigger, but that doesn't play
|
29
|
+
# nicely with links.
|
30
|
+
inner(el, opts)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Kramdown
|
2
|
+
module Parser
|
3
|
+
# Parses an extended Kramdown syntax with support for inline glosses.
|
4
|
+
# Everything in this class is internal.
|
5
|
+
class Hierogloss < ::Kramdown::Parser::Kramdown
|
6
|
+
def initialize(source, options)
|
7
|
+
super
|
8
|
+
@span_parsers.unshift(:translit)
|
9
|
+
@block_parsers.unshift(:gloss)
|
10
|
+
end
|
11
|
+
|
12
|
+
TRANSLIT_START = /{.*?}/
|
13
|
+
|
14
|
+
def parse_translit
|
15
|
+
@src.pos += @src.matched_size
|
16
|
+
mdc = @src.matched[1..-2]
|
17
|
+
em = Element.new(:em, nil, 'class' => 'hgls-l')
|
18
|
+
em.children <<
|
19
|
+
Element.new(:text, ::Hierogloss::TransliterationRow.fancy(mdc))
|
20
|
+
@tree.children << em
|
21
|
+
end
|
22
|
+
define_parser(:translit, TRANSLIT_START, '{')
|
23
|
+
|
24
|
+
GLOSS_START = /^(H|L|G|T):/
|
25
|
+
GLOSS_MATCH = /((^(H|L|G|T):.*)\r?\n)*/
|
26
|
+
|
27
|
+
def parse_gloss
|
28
|
+
start_line_number = @src.current_line_number
|
29
|
+
data = @src.scan(self.class::GLOSS_MATCH)
|
30
|
+
@tree.children.concat(::Hierogloss::Gloss.new(data).to_kramdown)
|
31
|
+
true
|
32
|
+
end
|
33
|
+
|
34
|
+
define_parser(:gloss, GLOSS_START)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/src/Gardiner.ttf
ADDED
Binary file
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'minitest_helper'
|
3
|
+
|
4
|
+
class TestDictionary < Minitest::Test
|
5
|
+
def assert_hw(headword, word)
|
6
|
+
assert_equal(headword, Hierogloss::Dictionary.headword(word))
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_should_leave_simple_headwords_alone
|
10
|
+
assert_hw("xr", "xr")
|
11
|
+
assert_hw("Hr", "Hr")
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_should_strip_parens
|
15
|
+
assert_hw("ny", "n(y)")
|
16
|
+
assert_hw("mAa-Hrw", "mAa(-Hrw)")
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_should_strip_clitics
|
20
|
+
assert_hw("ir", "ir=n")
|
21
|
+
assert_hw("im", "im=s")
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_should_remove_dot_before_t
|
25
|
+
assert_hw("Sspt", "Ssp.t")
|
26
|
+
assert_hw("Hmt", "Hm.t")
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_should_strip_plurals
|
30
|
+
assert_hw("Sspt", "Ssp.wt")
|
31
|
+
assert_hw("hrw", "hrw.w")
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_should_strip_verb_endings
|
35
|
+
assert_hw("ir", "ir.n=f")
|
36
|
+
assert_hw("Dd", "Dd.n")
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_should_provide_gardiner_signs_for_most_signs
|
40
|
+
assert_equal("A1", Hierogloss::Dictionary.gardiner("π"))
|
41
|
+
assert_equal("D4", Hierogloss::Dictionary.gardiner("πΉ"))
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_should_not_provide_gardiner_signs_for_uniliterals
|
45
|
+
# Let's not link these common characters.
|
46
|
+
"πΏππππ
±π²ππͺππ
ππππππ‘ππ΄πππ‘πΌππΏπ§π".each_char do |c|
|
47
|
+
assert_nil(Hierogloss::Dictionary.gardiner(c), "should not translate #{c}")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/test/test_gloss.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'minitest_helper'
|
3
|
+
|
4
|
+
class TestGloss < MiniTest::Test
|
5
|
+
include Hierogloss
|
6
|
+
|
7
|
+
def setup
|
8
|
+
input = <<EOD
|
9
|
+
H: πππ€ | πππ
|
10
|
+
L: s | s.t
|
11
|
+
G: homme | femme
|
12
|
+
T: l'homme et la femme
|
13
|
+
EOD
|
14
|
+
@gloss = Hierogloss::Gloss.new(input)
|
15
|
+
end
|
16
|
+
|
17
|
+
def assert_row(type, raw_cells, row)
|
18
|
+
assert_instance_of(type, row)
|
19
|
+
refute(row.span?)
|
20
|
+
assert_equal(raw_cells, row.raw_cells)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_should_parse_gloss_into_appropriate_rows
|
24
|
+
assert_equal(4, @gloss.rows.length)
|
25
|
+
assert_row(HieroglyphRow, ["πππ€", "πππ"], @gloss.rows[0])
|
26
|
+
assert_row(TransliterationRow, ["s", "s.t"], @gloss.rows[1])
|
27
|
+
assert_row(Row, ["homme", "femme"], @gloss.rows[2])
|
28
|
+
|
29
|
+
# Translations don't have cells.
|
30
|
+
assert_instance_of(TranslationRow, @gloss.rows[3])
|
31
|
+
assert(@gloss.rows[3].span?)
|
32
|
+
assert_equal("l'homme et la femme", @gloss.rows[3].text)
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_should_be_convertible_to_a_list_of_kramdown_elements
|
36
|
+
# We don't actually care what's in there; we just want to render
|
37
|
+
# something plausible.
|
38
|
+
kramdown = @gloss.to_kramdown
|
39
|
+
assert_instance_of(Array, kramdown)
|
40
|
+
assert(kramdown.length > 0)
|
41
|
+
kramdown.each {|k| assert_instance_of(Kramdown::Element, k) }
|
42
|
+
end
|
43
|
+
end
|