Skip to content

Commit 7007237

Browse files
two urlformat varieties
1 parent 54370b3 commit 7007237

File tree

5 files changed

+74
-17
lines changed

5 files changed

+74
-17
lines changed

syrinx/config.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from __future__ import annotations
2-
from typing import Any, Optional, TYPE_CHECKING
2+
from typing import Optional, TYPE_CHECKING
33
from os.path import isfile, join, abspath
44
if TYPE_CHECKING:
55
from argparse import Namespace
@@ -11,10 +11,11 @@ class SyrinxConfiguration:
1111
domain: Optional[str]
1212
environment: str
1313
verbose: bool
14+
urlformat: str
1415

1516
def __str__(self) -> str:
1617
lines = []
17-
for key in ('clean', 'domain', 'environment', 'verbose'):
18+
for key in ('clean', 'domain', 'environment', 'verbose', 'urlformat'):
1819
val = getattr(self, key)
1920
if isinstance(val, str):
2021
val = f'"{val}"'
@@ -30,6 +31,7 @@ def configure(args: Namespace) -> SyrinxConfiguration:
3031
config.domain = None
3132
config.verbose = False
3233
config.environment = 'default'
34+
config.urlformat = 'filesystem'
3335
root_dir = getattr(args, 'root_dir', '.')
3436
cfg_fpath = join(abspath(root_dir), 'syrinx.cfg')
3537
if isfile(cfg_fpath):
@@ -49,8 +51,10 @@ def configure(args: Namespace) -> SyrinxConfiguration:
4951
config.verbose = val.lower() == 'true'
5052
if key == 'environment':
5153
config.environment = val
54+
if key == 'urlformat':
55+
config.urlformat = val
5256

53-
for key in ('clean', 'domain', 'verbose', 'environment'):
57+
for key in ('clean', 'domain', 'verbose', 'environment', 'urlformat'):
5458
if hasattr(args, key):
5559
setattr(config, key, getattr(args, key))
5660
return config

syrinx/read.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ class BuildMetaInfo:
2121

2222
def __init__(self, config: SyrinxConfiguration) -> None:
2323
self.environment = config.environment
24-
self.domain = config.domain
2524
self.timestamp = datetime.now(tz=UTC)
2625
self.syrinx_version = version('syrinx')
2726

@@ -36,12 +35,15 @@ class ContentNode:
3635
buildPage: bool
3736
path: str
3837
meta: BuildMetaInfo
38+
config: SyrinxConfiguration
3939

40-
def __init__(self):
40+
def __init__(self, meta: BuildMetaInfo, config: SyrinxConfiguration):
4141
self.buildPage = False
4242
self.leaves = []
4343
self.branches = []
4444
self.sequenceNumber = SYS_MAX_SIZE
45+
self.meta = meta
46+
self.config = config
4547

4648
@property
4749
def title(self) -> str:
@@ -54,8 +56,11 @@ def title(self) -> str:
5456
def address(self) -> Optional[str]:
5557
"""Full, canonical URL of this node
5658
"""
57-
if self.meta.domain is not None:
58-
return f'https://{self.meta.domain}{self.path}/'
59+
if self.config.domain is not None:
60+
if self.config.urlformat == 'clean':
61+
return f'https://{self.config.domain}{self.path}'
62+
else:
63+
return f'https://{self.config.domain}{self.path}/'
5964

6065
@property
6166
def lastModified(self) -> Optional[str]:
@@ -86,14 +91,13 @@ def read(root_dir: str, config: SyrinxConfiguration) -> ContentNode:
8691
content_dir = join(root_dir, 'content')
8792

8893
tree: Dict[str, ContentNode] = dict()
89-
root = ContentNode()
94+
root = ContentNode(meta, config)
9095
root.name = ''
9196
root.meta = meta
9297
for (dirpath, _, fnames) in walk(content_dir):
9398

94-
indexNode = ContentNode()
99+
indexNode = ContentNode(meta, config)
95100
indexNode.name = basename(dirpath)
96-
indexNode.meta = meta
97101
if dirpath == content_dir:
98102
indexNode = root
99103
if 'index.md' not in fnames:
@@ -119,10 +123,9 @@ def read(root_dir: str, config: SyrinxConfiguration) -> ContentNode:
119123
node = indexNode
120124
node.path = dirpath.replace(content_dir, '')
121125
else:
122-
node = ContentNode()
126+
node = ContentNode(meta, config)
123127
node.name = name
124128
node.path = join(dirpath.replace(content_dir, ''), node.name)
125-
node.meta = meta
126129
indexNode.leaves.append(node)
127130

128131
node.front = fm_dict

tests/config.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ def test_defaults(self, _, isfile):
2525
self.assertFalse(config.verbose)
2626
self.assertTrue(config.clean)
2727
self.assertEqual(config.environment, 'default')
28+
self.assertEqual(config.urlformat, 'filesystem')
2829

2930
@patch('syrinx.config.isfile')
3031
@patch('syrinx.config.open', new_callable=mock_open)
@@ -36,13 +37,15 @@ def test_file(self, mocked_open, isfile):
3637
verbose = true
3738
environment = "staging"
3839
clean = false
40+
urlformat = "clean"
3941
"""
4042
args = Namespace()
4143
config = configure(args)
4244
self.assertEqual(config.domain, 'some.where.bla')
4345
self.assertTrue(config.verbose)
4446
self.assertFalse(config.clean)
4547
self.assertEqual(config.environment, 'staging')
48+
self.assertEqual(config.urlformat, 'clean')
4649

4750
@patch('syrinx.config.isfile')
4851
@patch('syrinx.config.open', new_callable=mock_open)
@@ -54,17 +57,20 @@ def test_cli(self, mocked_open, isfile):
5457
domain = "some.where.bla"
5558
verbose = true
5659
environment = "staging"
60+
urlformat = "clean"
5761
"""
5862
args = Namespace()
5963
args.domain = 'not.there.bla'
6064
args.verbose = False
6165
args.environment = 'production'
6266
args.clean = True
67+
args.urlformat = 'clean'
6368
config = configure(args)
6469
self.assertEqual(config.domain, 'not.there.bla')
6570
self.assertFalse(config.verbose)
6671
self.assertEqual(config.environment, 'production')
6772
self.assertTrue(config.clean)
73+
self.assertEqual(config.urlformat, 'clean')
6874

6975
def test_configuration_stringifiable(self):
7076
"""SyrinxConfiguration objects should convert to readable
@@ -76,5 +82,11 @@ def test_configuration_stringifiable(self):
7682
config.environment = 'default'
7783
config.verbose = False
7884
config.clean = True
85+
config.urlformat = 'filesystem'
7986
self.assertEqual(str(config),
80-
'\tclean = true\n\tdomain = "some.where.bla"\n\tenvironment = "default"\n\tverbose = false')
87+
'\tclean = true\n'
88+
'\tdomain = "some.where.bla"\n'
89+
'\tenvironment = "default"\n'
90+
'\tverbose = false\n'
91+
'\turlformat = "filesystem"'
92+
)

tests/content_node.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ class ContentNodeTests(TestCase):
55

66
def test_follows_buildPage(self):
77
from syrinx.read import ContentNode
8-
node = ContentNode()
8+
node = ContentNode(None, None)
99
node.name = 'foo_bar'
1010
node.front = dict()
1111
self.assertEqual(node.title, 'Foo Bar')

tests/read.py

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,11 @@ def test_read_adds_build_info(self, datetime, read_file, walk):
7070

7171
@patch('syrinx.read.walk')
7272
@patch('syrinx.read.read_file')
73-
def test_read_address(self, read_file, walk):
74-
"""
73+
def test_read_address_filesystem(self, read_file, walk):
74+
"""With the "filesystem" style, terminal branches have trailing slashes,
75+
and leaves have file extensions.
76+
77+
This style typically works out-of-the-box with web server software.
7578
"""
7679
read_file.return_value = dict(), ''
7780
walk.return_value = [
@@ -82,8 +85,43 @@ def test_read_address(self, read_file, walk):
8285
from syrinx.read import read
8386
config = Mock()
8487
config.domain = 'loop.xyz'
88+
config.urlformat = 'filesystem'
8589
root = read('/pth', config)
86-
self.assertEqual(root.address, 'https://loop.xyz/')
90+
self.assertEqual(root.address, 'https://loop.xyz')
8791
self.assertEqual(root.branches[0].address, 'https://loop.xyz/foo/')
92+
self.assertEqual(root.branches[0].leaves[0].address,
93+
'https://loop.xyz/foo/boz.html')
8894
self.assertEqual(root.branches[0].branches[0].address,
8995
'https://loop.xyz/foo/bar/')
96+
97+
@patch('syrinx.read.walk')
98+
@patch('syrinx.read.read_file')
99+
def test_read_address_clean(self, read_file, walk):
100+
"""With the "clean" style, terminal branches and leaves
101+
do not have trailing slashes or file extensions
102+
"""
103+
read_file.return_value = dict(), ''
104+
walk.return_value = [
105+
('/pth/content', None, ['index.md']),
106+
('/pth/content/bar', None, ['index.md', 'boz.md']),
107+
('/pth/content/foo', None, ['index.md']),
108+
('/pth/content/foo/bar', None, ['index.md']),
109+
]
110+
from syrinx.read import read
111+
config = Mock()
112+
config.domain = 'loop.xyz'
113+
config.urlformat = 'clean'
114+
root = read('/pth', config)
115+
self.assertEqual(root.address, 'https://loop.xyz')
116+
# this page has sub-branches, i.e. is a directory,
117+
# so comes with trailing slash:
118+
self.assertEqual(root.branches[0].address, 'https://loop.xyz/bar/')
119+
# this page has leaves, i.e. is a directory,
120+
# so comes with trailing slash:
121+
self.assertEqual(root.branches[1].address, 'https://loop.xyz/foo/')
122+
# leaves dont get a trailing slash:
123+
self.assertEqual(root.branches[0].leaves[0].address,
124+
'https://loop.xyz/foo/boz')
125+
# branches without sub-branches don't get a slash
126+
self.assertEqual(root.branches[0].branches[0].address,
127+
'https://loop.xyz/foo/bar')

0 commit comments

Comments
 (0)