refactor: make all operators generators
Except `format.counter`, of course.
This commit is contained in:
parent
8179e121f5
commit
1418055706
1 changed files with 50 additions and 54 deletions
|
|
@ -49,21 +49,22 @@ class consume:
|
|||
class lines(Consume):
|
||||
"""Consume line by line."""
|
||||
def __call__(self, stream):
|
||||
return stream.readlines()
|
||||
for line in stream:
|
||||
yield line
|
||||
|
||||
class paragraphs(Consume):
|
||||
"""Consume paragraph by paragraph (separated by an empty line)."""
|
||||
def __call__(self, stream):
|
||||
pars = []
|
||||
current = ""
|
||||
for item in stream.readlines():
|
||||
for item in stream:
|
||||
# Not counting spaces as legit content.
|
||||
if item.strip():
|
||||
current += item
|
||||
else:
|
||||
pars.append( current )
|
||||
yield current
|
||||
current = ""
|
||||
return pars
|
||||
if current.strip():
|
||||
yield current
|
||||
|
||||
class sections(Consume):
|
||||
"""Consume section by section. A new section starts when a line matches the `mark` regexp. If `skip` is set to 'skip', the marked line is not consumed."""
|
||||
|
|
@ -77,19 +78,17 @@ class consume:
|
|||
self.skip = bool(skip)
|
||||
|
||||
def __call__(self, stream):
|
||||
sec = []
|
||||
current = ""
|
||||
for item in stream.readlines():
|
||||
for item in stream:
|
||||
if re.match(self.mark, item[0]):
|
||||
sec.append( current )
|
||||
yield current
|
||||
if self.skip:
|
||||
current = ""
|
||||
else:
|
||||
current = item
|
||||
else:
|
||||
current += item
|
||||
sec.append( current )
|
||||
return sec
|
||||
yield current
|
||||
|
||||
class nlines(Consume):
|
||||
"""Consume by groups of `nb` lines."""
|
||||
|
|
@ -97,19 +96,17 @@ class consume:
|
|||
self.nb = int(nb)
|
||||
|
||||
def __call__(self, stream):
|
||||
sec = []
|
||||
count = 0
|
||||
current = ""
|
||||
for item in stream.readlines():
|
||||
for item in stream:
|
||||
if count >= self.nb:
|
||||
sec.append( current )
|
||||
yield current
|
||||
current = ""
|
||||
count = 0
|
||||
else:
|
||||
current += item
|
||||
count += 1
|
||||
sec.append( current )
|
||||
return sec
|
||||
yield current
|
||||
|
||||
|
||||
class format:
|
||||
|
|
@ -120,7 +117,8 @@ class format:
|
|||
class asis(Format):
|
||||
"""Do not format anything."""
|
||||
def __call__(self, items):
|
||||
return items
|
||||
for item in items:
|
||||
yield item
|
||||
|
||||
class trim(Format):
|
||||
"""Split items if their length is longer than `max`, and create new items with the remaining parts."""
|
||||
|
|
@ -137,57 +135,47 @@ class format:
|
|||
yield item
|
||||
|
||||
def __call__(self, items):
|
||||
trimmed = []
|
||||
for item in items:
|
||||
for separated in self.trim(item):
|
||||
trimmed.append(separated)
|
||||
return trimmed
|
||||
yield separated
|
||||
|
||||
class eol(Format):
|
||||
"""Add an end of line after the item."""
|
||||
def __call__(self, items):
|
||||
eoled = []
|
||||
for item in items:
|
||||
eoled.append( item + "\n" )
|
||||
return eoled
|
||||
yield item + "\n"
|
||||
|
||||
class strip(Format):
|
||||
"""Remove any space character around the item."""
|
||||
def __call__(self, items):
|
||||
stripped = []
|
||||
for item in items:
|
||||
stripped.append( item.strip() )
|
||||
return stripped
|
||||
yield item.strip()
|
||||
|
||||
class skip(Format):
|
||||
"""Skip items containing only spaces or being empty."""
|
||||
def __call__(self, items):
|
||||
res = []
|
||||
for item in items:
|
||||
if item.strip():
|
||||
res.append( item )
|
||||
return res
|
||||
yield item
|
||||
|
||||
class glue(Format):
|
||||
"""Glue consecutive items together if they are not separated by an empty one."""
|
||||
def __call__(self, items):
|
||||
glued = []
|
||||
current = ""
|
||||
for item in items:
|
||||
if item.strip():
|
||||
current += item
|
||||
else:
|
||||
glued.append( current )
|
||||
yield current
|
||||
current = ""
|
||||
return glued
|
||||
if current.strip():
|
||||
yield current
|
||||
|
||||
class panel(Format):
|
||||
"""Surround each item by an ascii-art box. NOTE: only works when lifted on stdout."""
|
||||
def __call__(self, items):
|
||||
panel = []
|
||||
for item in items:
|
||||
panel.append( Panel.fit(item.strip()) )
|
||||
return panel
|
||||
yield Panel.fit(item.strip())
|
||||
|
||||
class counter(Format):
|
||||
"""Add a counter at the end of each items, with the current index and the total. If `end` is given, it is added at the very last item. If `sep` is given, it is appended to the item before the counter itself."""
|
||||
|
|
@ -195,14 +183,16 @@ class format:
|
|||
self.sep = sep
|
||||
self.end = end
|
||||
|
||||
def __call__(self, items):
|
||||
def __call__(self, counted):
|
||||
items = list(counted) # Consume everything at once.
|
||||
total = len(items)
|
||||
res = []
|
||||
for i,item in enumerate(items):
|
||||
res.append(f"{item}{self.sep}{i+1}/{total}")
|
||||
if res:
|
||||
res[-1] += self.end
|
||||
return res
|
||||
for r in res:
|
||||
yield r
|
||||
|
||||
class suffix(Format):
|
||||
"""Add the `content` string after each item. If `sep` is given, it is appended to the item before the content and after the item."""
|
||||
|
|
@ -211,7 +201,8 @@ class format:
|
|||
self.sep = sep
|
||||
|
||||
def __call__(self, items):
|
||||
return [i+self.sep+self.content for i in items]
|
||||
for i in items:
|
||||
yield i+self.sep+self.content
|
||||
|
||||
class prefix(Format):
|
||||
"""Add the `content` string before each item. If `sep` is given, it is prepended to the item after the content and before the item."""
|
||||
|
|
@ -220,18 +211,26 @@ class format:
|
|||
self.sep = sep
|
||||
|
||||
def __call__(self, items):
|
||||
return [self.content+self.sep+i for i in items]
|
||||
for i in items:
|
||||
yield self.content+self.sep+i
|
||||
|
||||
|
||||
class lift:
|
||||
class Lift:
|
||||
def __call__(self, items):
|
||||
def call(self, items):
|
||||
raise NotImplementedError
|
||||
|
||||
def __call__(self, items):
|
||||
count = 0
|
||||
for item in items:
|
||||
self.call(item)
|
||||
count += 1
|
||||
logger.debug(f"│ │ ├ {count}th item")
|
||||
logger.debug(f"│ │ └OK {count} items")
|
||||
|
||||
class stdout(Lift):
|
||||
"""Print the items on the standard output."""
|
||||
def __call__(self, items):
|
||||
for item in items:
|
||||
def call(self, item):
|
||||
if item:
|
||||
if __debug__:
|
||||
print(item, end = '', file = sys.stdout, flush = True)
|
||||
|
|
@ -273,27 +272,24 @@ class Forthlifter:
|
|||
logger.debug(f"│ │ ├ {type(self.consumer).__name__}({type(streamer).__name__})")
|
||||
# Concatenate
|
||||
items += self.consumer(streamer())
|
||||
logger.debug(f"│ │ ├ {len(items)} items")
|
||||
logger.debug(f"│ │ └OK {len(items)} items")
|
||||
logger.debug(f"│ │ └OK")
|
||||
return items
|
||||
|
||||
def format(self, items):
|
||||
logger.debug(f"│ ├ format {len(items)} items")
|
||||
logger.debug(f"│ ├ format")
|
||||
for formatter in self.formatters:
|
||||
logger.debug(f"│ │ ├ {type(formatter).__name__}")
|
||||
# Replace
|
||||
items = formatter(items)
|
||||
logger.debug(f"│ │ ├ {len(items)} items")
|
||||
logger.debug(f"│ │ └OK {len(items)} items")
|
||||
logger.debug(f"│ │ └OK")
|
||||
return items
|
||||
|
||||
def lift(self, items):
|
||||
logger.debug(f"│ ├ lift {len(items)} items")
|
||||
logger.debug(f"│ ├ lift")
|
||||
for lifter in self.lifters:
|
||||
logger.debug(f"│ │ ├ {type(lifter).__name__}")
|
||||
# Call
|
||||
lifter(items)
|
||||
logger.debug(f"│ │ └OK {len(items)} items")
|
||||
|
||||
def __call__(self):
|
||||
logger.debug("├ call")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue