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):
|
class lines(Consume):
|
||||||
"""Consume line by line."""
|
"""Consume line by line."""
|
||||||
def __call__(self, stream):
|
def __call__(self, stream):
|
||||||
return stream.readlines()
|
for line in stream:
|
||||||
|
yield line
|
||||||
|
|
||||||
class paragraphs(Consume):
|
class paragraphs(Consume):
|
||||||
"""Consume paragraph by paragraph (separated by an empty line)."""
|
"""Consume paragraph by paragraph (separated by an empty line)."""
|
||||||
def __call__(self, stream):
|
def __call__(self, stream):
|
||||||
pars = []
|
|
||||||
current = ""
|
current = ""
|
||||||
for item in stream.readlines():
|
for item in stream:
|
||||||
# Not counting spaces as legit content.
|
# Not counting spaces as legit content.
|
||||||
if item.strip():
|
if item.strip():
|
||||||
current += item
|
current += item
|
||||||
else:
|
else:
|
||||||
pars.append( current )
|
yield current
|
||||||
current = ""
|
current = ""
|
||||||
return pars
|
if current.strip():
|
||||||
|
yield current
|
||||||
|
|
||||||
class sections(Consume):
|
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."""
|
"""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)
|
self.skip = bool(skip)
|
||||||
|
|
||||||
def __call__(self, stream):
|
def __call__(self, stream):
|
||||||
sec = []
|
|
||||||
current = ""
|
current = ""
|
||||||
for item in stream.readlines():
|
for item in stream:
|
||||||
if re.match(self.mark, item[0]):
|
if re.match(self.mark, item[0]):
|
||||||
sec.append( current )
|
yield current
|
||||||
if self.skip:
|
if self.skip:
|
||||||
current = ""
|
current = ""
|
||||||
else:
|
else:
|
||||||
current = item
|
current = item
|
||||||
else:
|
else:
|
||||||
current += item
|
current += item
|
||||||
sec.append( current )
|
yield current
|
||||||
return sec
|
|
||||||
|
|
||||||
class nlines(Consume):
|
class nlines(Consume):
|
||||||
"""Consume by groups of `nb` lines."""
|
"""Consume by groups of `nb` lines."""
|
||||||
|
|
@ -97,19 +96,17 @@ class consume:
|
||||||
self.nb = int(nb)
|
self.nb = int(nb)
|
||||||
|
|
||||||
def __call__(self, stream):
|
def __call__(self, stream):
|
||||||
sec = []
|
|
||||||
count = 0
|
count = 0
|
||||||
current = ""
|
current = ""
|
||||||
for item in stream.readlines():
|
for item in stream:
|
||||||
if count >= self.nb:
|
if count >= self.nb:
|
||||||
sec.append( current )
|
yield current
|
||||||
current = ""
|
current = ""
|
||||||
count = 0
|
count = 0
|
||||||
else:
|
else:
|
||||||
current += item
|
current += item
|
||||||
count += 1
|
count += 1
|
||||||
sec.append( current )
|
yield current
|
||||||
return sec
|
|
||||||
|
|
||||||
|
|
||||||
class format:
|
class format:
|
||||||
|
|
@ -120,7 +117,8 @@ class format:
|
||||||
class asis(Format):
|
class asis(Format):
|
||||||
"""Do not format anything."""
|
"""Do not format anything."""
|
||||||
def __call__(self, items):
|
def __call__(self, items):
|
||||||
return items
|
for item in items:
|
||||||
|
yield item
|
||||||
|
|
||||||
class trim(Format):
|
class trim(Format):
|
||||||
"""Split items if their length is longer than `max`, and create new items with the remaining parts."""
|
"""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
|
yield item
|
||||||
|
|
||||||
def __call__(self, items):
|
def __call__(self, items):
|
||||||
trimmed = []
|
|
||||||
for item in items:
|
for item in items:
|
||||||
for separated in self.trim(item):
|
for separated in self.trim(item):
|
||||||
trimmed.append(separated)
|
yield separated
|
||||||
return trimmed
|
|
||||||
|
|
||||||
class eol(Format):
|
class eol(Format):
|
||||||
"""Add an end of line after the item."""
|
"""Add an end of line after the item."""
|
||||||
def __call__(self, items):
|
def __call__(self, items):
|
||||||
eoled = []
|
|
||||||
for item in items:
|
for item in items:
|
||||||
eoled.append( item + "\n" )
|
yield item + "\n"
|
||||||
return eoled
|
|
||||||
|
|
||||||
class strip(Format):
|
class strip(Format):
|
||||||
"""Remove any space character around the item."""
|
"""Remove any space character around the item."""
|
||||||
def __call__(self, items):
|
def __call__(self, items):
|
||||||
stripped = []
|
|
||||||
for item in items:
|
for item in items:
|
||||||
stripped.append( item.strip() )
|
yield item.strip()
|
||||||
return stripped
|
|
||||||
|
|
||||||
class skip(Format):
|
class skip(Format):
|
||||||
"""Skip items containing only spaces or being empty."""
|
"""Skip items containing only spaces or being empty."""
|
||||||
def __call__(self, items):
|
def __call__(self, items):
|
||||||
res = []
|
|
||||||
for item in items:
|
for item in items:
|
||||||
if item.strip():
|
if item.strip():
|
||||||
res.append( item )
|
yield item
|
||||||
return res
|
|
||||||
|
|
||||||
class glue(Format):
|
class glue(Format):
|
||||||
"""Glue consecutive items together if they are not separated by an empty one."""
|
"""Glue consecutive items together if they are not separated by an empty one."""
|
||||||
def __call__(self, items):
|
def __call__(self, items):
|
||||||
glued = []
|
|
||||||
current = ""
|
current = ""
|
||||||
for item in items:
|
for item in items:
|
||||||
if item.strip():
|
if item.strip():
|
||||||
current += item
|
current += item
|
||||||
else:
|
else:
|
||||||
glued.append( current )
|
yield current
|
||||||
current = ""
|
current = ""
|
||||||
return glued
|
if current.strip():
|
||||||
|
yield current
|
||||||
|
|
||||||
class panel(Format):
|
class panel(Format):
|
||||||
"""Surround each item by an ascii-art box. NOTE: only works when lifted on stdout."""
|
"""Surround each item by an ascii-art box. NOTE: only works when lifted on stdout."""
|
||||||
def __call__(self, items):
|
def __call__(self, items):
|
||||||
panel = []
|
|
||||||
for item in items:
|
for item in items:
|
||||||
panel.append( Panel.fit(item.strip()) )
|
yield Panel.fit(item.strip())
|
||||||
return panel
|
|
||||||
|
|
||||||
class counter(Format):
|
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."""
|
"""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.sep = sep
|
||||||
self.end = end
|
self.end = end
|
||||||
|
|
||||||
def __call__(self, items):
|
def __call__(self, counted):
|
||||||
|
items = list(counted) # Consume everything at once.
|
||||||
total = len(items)
|
total = len(items)
|
||||||
res = []
|
res = []
|
||||||
for i,item in enumerate(items):
|
for i,item in enumerate(items):
|
||||||
res.append(f"{item}{self.sep}{i+1}/{total}")
|
res.append(f"{item}{self.sep}{i+1}/{total}")
|
||||||
if res:
|
if res:
|
||||||
res[-1] += self.end
|
res[-1] += self.end
|
||||||
return res
|
for r in res:
|
||||||
|
yield r
|
||||||
|
|
||||||
class suffix(Format):
|
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."""
|
"""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
|
self.sep = sep
|
||||||
|
|
||||||
def __call__(self, items):
|
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):
|
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."""
|
"""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,25 +211,33 @@ class format:
|
||||||
self.sep = sep
|
self.sep = sep
|
||||||
|
|
||||||
def __call__(self, items):
|
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:
|
||||||
class Lift:
|
class Lift:
|
||||||
def __call__(self, items):
|
def call(self, items):
|
||||||
raise NotImplementedError
|
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):
|
class stdout(Lift):
|
||||||
"""Print the items on the standard output."""
|
"""Print the items on the standard output."""
|
||||||
def __call__(self, items):
|
def call(self, item):
|
||||||
for item in items:
|
if item:
|
||||||
if item:
|
if __debug__:
|
||||||
if __debug__:
|
print(item, end = '', file = sys.stdout, flush = True)
|
||||||
print(item, end = '', file = sys.stdout, flush = True)
|
|
||||||
else:
|
|
||||||
print(item, end = '')
|
|
||||||
else:
|
else:
|
||||||
logger.debug("Empty item")
|
print(item, end = '')
|
||||||
|
else:
|
||||||
|
logger.debug("Empty item")
|
||||||
|
|
||||||
|
|
||||||
class Forthlifter:
|
class Forthlifter:
|
||||||
|
|
@ -273,27 +272,24 @@ class Forthlifter:
|
||||||
logger.debug(f"│ │ ├ {type(self.consumer).__name__}({type(streamer).__name__})")
|
logger.debug(f"│ │ ├ {type(self.consumer).__name__}({type(streamer).__name__})")
|
||||||
# Concatenate
|
# Concatenate
|
||||||
items += self.consumer(streamer())
|
items += self.consumer(streamer())
|
||||||
logger.debug(f"│ │ ├ {len(items)} items")
|
logger.debug(f"│ │ └OK")
|
||||||
logger.debug(f"│ │ └OK {len(items)} items")
|
|
||||||
return items
|
return items
|
||||||
|
|
||||||
def format(self, items):
|
def format(self, items):
|
||||||
logger.debug(f"│ ├ format {len(items)} items")
|
logger.debug(f"│ ├ format")
|
||||||
for formatter in self.formatters:
|
for formatter in self.formatters:
|
||||||
logger.debug(f"│ │ ├ {type(formatter).__name__}")
|
logger.debug(f"│ │ ├ {type(formatter).__name__}")
|
||||||
# Replace
|
# Replace
|
||||||
items = formatter(items)
|
items = formatter(items)
|
||||||
logger.debug(f"│ │ ├ {len(items)} items")
|
logger.debug(f"│ │ └OK")
|
||||||
logger.debug(f"│ │ └OK {len(items)} items")
|
|
||||||
return items
|
return items
|
||||||
|
|
||||||
def lift(self, items):
|
def lift(self, items):
|
||||||
logger.debug(f"│ ├ lift {len(items)} items")
|
logger.debug(f"│ ├ lift")
|
||||||
for lifter in self.lifters:
|
for lifter in self.lifters:
|
||||||
logger.debug(f"│ │ ├ {type(lifter).__name__}")
|
logger.debug(f"│ │ ├ {type(lifter).__name__}")
|
||||||
# Call
|
# Call
|
||||||
lifter(items)
|
lifter(items)
|
||||||
logger.debug(f"│ │ └OK {len(items)} items")
|
|
||||||
|
|
||||||
def __call__(self):
|
def __call__(self):
|
||||||
logger.debug("├ call")
|
logger.debug("├ call")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue