Skip to content

Commit 816fa51

Browse files
committed
first step toward a better project layout.
1 parent 1aead68 commit 816fa51

4 files changed

Lines changed: 156 additions & 124 deletions

File tree

tests/test_block.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
from __future__ import unicode_literals
2+
23
from textile import Textile
4+
from textile.objects import Block
5+
36
try:
47
from collections import OrderedDict
58
except ImportError:
@@ -11,26 +14,30 @@ def test_block():
1114
expect = '\t<h1>foobar baby</h1>'
1215
assert result == expect
1316

14-
result = t.fBlock("bq", "", None, "", "Hello BlockQuote")
17+
b = Block(t, "bq", "", None, "", "Hello BlockQuote")
1518
expect = ('blockquote', OrderedDict(), 'p', OrderedDict(),
1619
'Hello BlockQuote')
20+
result = (b.outer_tag, b.outer_atts, b.inner_tag, b.inner_atts, b.content)
1721
assert result == expect
1822

19-
result = t.fBlock("bq", "", None, "http://google.com", "Hello BlockQuote")
23+
b = Block(t, "bq", "", None, "http://google.com", "Hello BlockQuote")
2024
citation = '{0}1:url'.format(t.uid)
2125
expect = ('blockquote', OrderedDict([('cite',
2226
'{0.uid}{0.refIndex}:url'.format(t))]), 'p', OrderedDict(),
2327
'Hello BlockQuote')
28+
result = (b.outer_tag, b.outer_atts, b.inner_tag, b.inner_atts, b.content)
2429
assert result == expect
2530

26-
result = t.fBlock("bc", "", None, "", 'printf "Hello, World";')
31+
b = Block(t, "bc", "", None, "", 'printf "Hello, World";')
2732
# the content of text will be turned shelved, so we'll asert only the
2833
# deterministic portions of the expected values, below
29-
expect = ('pre', OrderedDict(), 'code', OrderedDict(), 'shelve')
30-
assert result[0:3] == expect[0:3]
34+
expect = ('pre', OrderedDict(), 'code', OrderedDict())
35+
result = (b.outer_tag, b.outer_atts, b.inner_tag, b.inner_atts)
36+
assert result == expect
3137

32-
result = t.fBlock("h1", "", None, "", "foobar")
38+
b = Block(t, "h1", "", None, "", "foobar")
3339
expect = ('h1', OrderedDict(), '', OrderedDict(), 'foobar')
40+
result = (b.outer_tag, b.outer_atts, b.inner_tag, b.inner_atts, b.content)
3441
assert result == expect
3542

3643
def test_block_tags_false():

textile/core.py

Lines changed: 17 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
from textile.utils import (decode_high, encode_high, encode_html, generate_tag,
3030
has_raw_text, is_rel_url, is_valid_url, list_type, normalize_newlines,
3131
parse_attributes, pba)
32+
from textile.objects import Block
3233

3334

3435
try:
@@ -577,18 +578,19 @@ def block(self, text):
577578
# tag specified on this line.
578579
if match:
579580
tag, atts, ext, cite, content = match.groups()
580-
(outer_tag, outer_atts, inner_tag, inner_atts,
581-
content) = self.fBlock(**match.groupdict())
582-
inner_block = generate_tag(inner_tag, content, inner_atts)
581+
block = Block(self, **match.groupdict())
582+
inner_block = generate_tag(block.inner_tag, block.content,
583+
block.inner_atts)
583584
# code tags and raw text won't be indented inside outer_tag.
584-
if inner_tag != 'code' and not has_raw_text(inner_block):
585+
if block.inner_tag != 'code' and not has_raw_text(inner_block):
585586
inner_block = "\n\t\t{0}\n\t".format(inner_block)
586587
if ext:
587-
line = content
588+
line = block.content
588589
else:
589-
line = generate_tag(outer_tag, inner_block, outer_atts)
590+
line = generate_tag(block.outer_tag, inner_block,
591+
block.outer_atts)
590592
# pre tags and raw text won't be indented.
591-
if outer_tag != 'pre' and not has_raw_text(line):
593+
if block.outer_tag != 'pre' and not has_raw_text(line):
592594
line = "\t{0}".format(line)
593595
# no tag specified
594596
else:
@@ -598,13 +600,13 @@ def block(self, text):
598600
line = '{0}\n{1}'.format(out.pop(), line)
599601
whitespace = ' \t\n\r\f\v'
600602
if ext or not line[0] in whitespace:
601-
(outer_tag, outer_atts, inner_tag, inner_atts,
602-
content) = self.fBlock(tag, atts, ext, cite, line)
603-
if tag == 'p' and not has_raw_text(content):
604-
line = content
603+
block = Block(self, tag, atts, ext, cite, line)
604+
if block.tag == 'p' and not has_raw_text(block.content):
605+
line = block.content
605606
else:
606-
line = generate_tag(outer_tag, content, outer_atts)
607-
if outer_tag != 'pre' and not has_raw_text(line):
607+
line = generate_tag(block.outer_tag, block.content,
608+
block.outer_atts)
609+
if block.outer_tag != 'pre' and not has_raw_text(line):
608610
line = "\t{0}".format(line)
609611
else:
610612
line = self.graf(line)
@@ -622,113 +624,10 @@ def block(self, text):
622624
graf = ''
623625

624626
if ext:
625-
out.append(generate_tag(outer_tag, out.pop(), outer_atts))
627+
out.append(generate_tag(block.outer_tag, out.pop(),
628+
block.outer_atts))
626629
return '\n\n'.join(out)
627630

628-
def fBlock(self, tag, atts, ext, cite, content):
629-
att = atts
630-
attributes = parse_attributes(att)
631-
outer_tag = ''
632-
inner_tag = ''
633-
outer_atts = OrderedDict()
634-
inner_atts = OrderedDict()
635-
eat = False
636-
637-
if tag == 'p':
638-
# is this an anonymous block with a note definition?
639-
notedef_re = re.compile(r"""
640-
^note\# # start of note def marker
641-
(?P<label>[^%<*!@\#^([{{ {space}.]+) # label
642-
(?P<link>[*!^]?) # link
643-
(?P<att>{cls}) # att
644-
\.? # optional period.
645-
[{space}]+ # whitespace ends def marker
646-
(?P<content>.*)$ # content""".format(
647-
space=regex_snippets['space'], cls=cls_re_s),
648-
flags=re.X | re.U)
649-
notedef = notedef_re.sub(self.fParseNoteDefs, content)
650-
651-
# It will be empty if the regex matched and ate it.
652-
if '' == notedef:
653-
content = notedef
654-
return (outer_tag, outer_atts, inner_tag, inner_atts, content)
655-
656-
fns = re.search(r'fn(?P<fnid>{0}+)'.format(regex_snippets['digit']),
657-
tag, flags=re.U)
658-
if fns:
659-
tag = 'p'
660-
fnid = self.fn.get(fns.group('fnid'), None)
661-
if fnid is None:
662-
fnid = '{0}{1}'.format(self.linkPrefix,
663-
self._increment_link_index())
664-
665-
# If there is an author-specified ID goes on the wrapper & the
666-
# auto-id gets pushed to the <sup>
667-
supp_id = OrderedDict()
668-
669-
# if class has not been previously specified, set it to "footnote"
670-
if 'class' not in attributes:
671-
attributes.update({'class': 'footnote'})
672-
673-
# if there's no specified id, use the generated one.
674-
if 'id' not in attributes:
675-
attributes.update({'id': 'fn{0}'.format(fnid)})
676-
else:
677-
supp_id = parse_attributes('(#fn{0})'.format(fnid))
678-
679-
680-
if '^' not in att:
681-
sup = generate_tag('sup', fns.group('fnid'), supp_id)
682-
else:
683-
fnrev = generate_tag('a', fns.group('fnid'), {'href':
684-
'#fnrev{0}'.format(fnid)})
685-
sup = generate_tag('sup', fnrev, supp_id)
686-
687-
content = '{0} {1}'.format(sup, content)
688-
689-
if tag == 'bq':
690-
if cite:
691-
cite = self.shelveURL(cite)
692-
cite_att = OrderedDict(cite=cite)
693-
cite = ' cite="{0}"'.format(cite)
694-
else:
695-
cite = ''
696-
cite_att = OrderedDict()
697-
cite_att.update(attributes)
698-
outer_tag = 'blockquote'
699-
outer_atts = cite_att
700-
inner_tag = 'p'
701-
inner_atts = attributes
702-
eat = False
703-
704-
elif tag == 'bc' or tag == 'pre':
705-
i_tag = ''
706-
if tag == 'bc':
707-
i_tag = 'code'
708-
content = self.shelve(encode_html('{0}\n'.format(
709-
content.rstrip("\n"))))
710-
outer_tag = 'pre'
711-
outer_atts = attributes
712-
inner_tag = i_tag
713-
inner_atts = attributes
714-
eat = False
715-
716-
elif tag == 'notextile':
717-
content = self.shelve(content)
718-
719-
elif tag == '###':
720-
eat = True
721-
722-
else:
723-
outer_tag = tag
724-
outer_atts = attributes
725-
726-
if not eat:
727-
content = self.graf(content)
728-
else:
729-
content = ''
730-
return (outer_tag, outer_atts, inner_tag, inner_atts, content)
731-
732631
def footnoteRef(self, text):
733632
# somehow php-textile gets away with not capturing the space.
734633
return re.compile(r'(?<=\S)\[(?P<id>{0}+)(?P<nolink>!?)\]'

textile/objects/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .block import Block
2+
3+
__all__ = ['Block', ]

textile/objects/block.py

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
try:
2+
from collections import OrderedDict
3+
except ImportError:
4+
from ordereddict import OrderedDict
5+
try:
6+
import regex as re
7+
except ImportError:
8+
import re
9+
10+
from textile.regex_strings import cls_re_s, regex_snippets
11+
from textile.utils import encode_html, generate_tag, parse_attributes
12+
13+
14+
class Block(object):
15+
def __init__(self, textile, tag, atts, ext, cite, content):
16+
self.textile = textile
17+
self.tag = tag
18+
self.atts = atts
19+
self.ext = ext
20+
self.cite = cite
21+
self.content = content
22+
23+
self.attributes = parse_attributes(atts)
24+
self.outer_tag = ''
25+
self.inner_tag = ''
26+
self.outer_atts = OrderedDict()
27+
self.inner_atts = OrderedDict()
28+
self.eat = False
29+
self.process()
30+
31+
def process(self):
32+
if self.tag == 'p':
33+
# is this an anonymous block with a note definition?
34+
notedef_re = re.compile(r"""
35+
^note\# # start of note def marker
36+
(?P<label>[^%<*!@\#^([{{ {space}.]+) # label
37+
(?P<link>[*!^]?) # link
38+
(?P<att>{cls}) # att
39+
\.? # optional period.
40+
[{space}]+ # whitespace ends def marker
41+
(?P<content>.*)$ # content""".format(
42+
space=regex_snippets['space'], cls=cls_re_s),
43+
flags=re.X | re.U)
44+
notedef = notedef_re.sub(self.textile.fParseNoteDefs, self.content)
45+
46+
# It will be empty if the regex matched and ate it.
47+
if '' == notedef:
48+
self.content = notedef
49+
50+
fns = re.search(r'fn(?P<fnid>{0}+)'.format(regex_snippets['digit']),
51+
self.tag, flags=re.U)
52+
if fns:
53+
self.tag = 'p'
54+
fnid = self.textile.fn.get(fns.group('fnid'), None)
55+
if fnid is None:
56+
fnid = '{0}{1}'.format(self.textile.linkPrefix,
57+
self.textile._increment_link_index())
58+
59+
# If there is an author-specified ID goes on the wrapper & the
60+
# auto-id gets pushed to the <sup>
61+
supp_id = OrderedDict()
62+
63+
# if class has not been previously specified, set it to "footnote"
64+
if 'class' not in self.attributes:
65+
self.attributes.update({'class': 'footnote'})
66+
67+
# if there's no specified id, use the generated one.
68+
if 'id' not in self.attributes:
69+
self.attributes.update({'id': 'fn{0}'.format(fnid)})
70+
else:
71+
supp_id = parse_attributes('(#fn{0})'.format(fnid))
72+
73+
74+
if '^' not in self.atts:
75+
sup = generate_tag('sup', fns.group('fnid'), supp_id)
76+
else:
77+
fnrev = generate_tag('a', fns.group('fnid'), {'href':
78+
'#fnrev{0}'.format(fnid)})
79+
sup = generate_tag('sup', fnrev, supp_id)
80+
81+
self.content = '{0} {1}'.format(sup, self.content)
82+
83+
if self.tag == 'bq':
84+
if self.cite:
85+
self.cite = self.textile.shelveURL(self.cite)
86+
cite_att = OrderedDict(cite=self.cite)
87+
self.cite = ' cite="{0}"'.format(self.cite)
88+
else:
89+
self.cite = ''
90+
cite_att = OrderedDict()
91+
cite_att.update(self.attributes)
92+
self.outer_tag = 'blockquote'
93+
self.outer_atts = cite_att
94+
self.inner_tag = 'p'
95+
self.inner_atts = self.attributes
96+
self.eat = False
97+
98+
elif self.tag == 'bc' or self.tag == 'pre':
99+
i_tag = ''
100+
if self.tag == 'bc':
101+
i_tag = 'code'
102+
self.content = self.textile.shelve(encode_html('{0}\n'.format(
103+
self.content.rstrip("\n"))))
104+
self.outer_tag = 'pre'
105+
self.outer_atts = self.attributes
106+
self.inner_tag = i_tag
107+
self.inner_atts = self.attributes
108+
self.eat = False
109+
110+
elif self.tag == 'notextile':
111+
self.content = self.textile.shelve(self.content)
112+
113+
elif self.tag == '###':
114+
self.eat = True
115+
116+
else:
117+
self.outer_tag = self.tag
118+
self.outer_atts = self.attributes
119+
120+
if not self.eat:
121+
self.content = self.textile.graf(self.content)
122+
else:
123+
self.content = ''

0 commit comments

Comments
 (0)