Commits

Lynn Rees committed e942839 Merge

automerge

  • Participants
  • Parent commits 2b35204, 725680c

Comments (0)

Files changed (10)

 288c7a69971fd099e5d9b90afd76e3bbf82c683d 0.4.7
 34ebc8ed5a01c2127d3624920d062b31e9dcc628 0.4.8
 5439767de340107d4a8dda3f1529fd43a87da4a0 0.4.9
+b3dd7187e9ac3410aabd8868bb7152de64b5e70d 0.4.10
 
 setup(
     name='twoq',
-    version='0.4.10',
+    version='0.4.11',
     description='iterator chaining, underscored by a two-headed queue',
     long_description=open(join(getcwd(), 'README.rst'), 'r').read(),
     keywords='queue generator utility iterator functional programming',
 
 __all__ = ('twoq', 'manq', 'autoq', 'port')
 
-__version__ = (0, 4, 10)
+__version__ = (0, 4, 11)

twoq/filtering.py

     '''collecting mixin'''
 
     @staticmethod
-    def _pick(names, iterable):
-        '''
-        collect attributes of things in iterable
-
-        @param names: sequence of names
-        @param iterable: an iterable
-        '''
-        attrfind = attrgetter(*names)
-        for thing in iterable:
-            try:
-                yield attrfind(thing)
-            except AttributeError:
-                pass
-
-    @staticmethod
     def _members(iterable):
         '''
         collect members of things
                 yield key, thing
 
     @classmethod
+    def _walk(cls, truth, subcall, transform, iterable):
+        '''
+        collect members of things
+
+        @param call: "Truth" filter
+        @param truth: second "Truth" filter
+        @param iterable: an iterable
+        '''
+        getattr_, AttributeError_, walk_ = getattr, AttributeError, cls._walk
+        for key in cls._ifilter(truth, dir(iterable)):
+            try:
+                thing = getattr_(iterable, key)
+            except AttributeError_:
+                pass
+            else:
+                if subcall(thing):
+                    yield key, transform(
+                        walk_(truth, subcall, transform, thing)
+                    )
+                else:
+                    yield key, thing
+
+    @classmethod
     def _mfilter(cls, call, iterable):
         '''
         filter members of things
             yield i
 
     @staticmethod
+    def _pick(names, iterable):
+        '''
+        collect attributes of things in iterable
+
+        @param names: sequence of names
+        @param iterable: an iterable
+        '''
+        attrfind = attrgetter(*names)
+        for thing in iterable:
+            try:
+                yield attrfind(thing)
+            except AttributeError:
+                pass
+
+    @staticmethod
     def _pluck(keys, iterable, _itemgetter=itemgetter):
         '''
         collect values of things in iterable
             return self._xtend(self._ichain(self._imap(
                 self._partial(self._mfilter, self._call), self._iterable,
             )))
+            
+    def extract(self):
+        '''extract object members from incoming things'''
+        with self._context():
+            walk_ = self._walk
+            call_, alt_, wrap_ = self._call, self._altcall, self._wrapper
+            return self._xtend(self._ichain(self._imap(
+                lambda x: walk_(call_, alt_, wrap_, x), self._iterable,
+            )))
 
     def pick(self, *names):
         '''collect object attributes from incoming things by their `*names`'''
         # outgoing things
         self.outgoing = outgoing
         # current callable
-        self._call = None
+        self._call = lambda x: x
+        # current alt callable
+        self._altcall = lambda x: x
+        # clear wrapper
+        self._wrapper = self._list
         # reset postitional arguments
         self._args = ()
         # reset keyword arguments
 
     def clear(self):
         '''clear every thing'''
-        return self.detap().outclear().inclear()._wclear()._uclear()
+        return (
+            self.detap().unwrap().dealt().outclear().inclear()._wclear()
+            ._uclear()
+        )
 
     ###########################################################################
     ## context rotation #######################################################
         # set current callable
         self._call = call
         return self
+    
+    def alt(self, call):
+        '''
+        set alternative current callable
+
+        @param call: an alternative callable
+        '''
+        self._altcall = call
+        return self
 
     def detap(self):
         '''clear current callable'''
         self._args = ()
         # reset keyword arguments
         self._kw = {}
-        # reset current callable
-        self._call = None
+        # reset current callable (default is identity)
+        self._call = lambda x: x
+        return self
+    
+    def dealt(self):
+        '''clear current alternative callable'''
+        self._altcall = lambda x: x
         return self
 
-    unwrap = detap
-
-    def wrap(self, call):
+    def factory(self, call):
         '''
         build current callable from factory
 
         @param call: a callable
         '''
-        def factory(*args, **kw):
+        def wrap(*args, **kw):
             return call(*args, **kw)
-        return self.tap(factory)
+        return self.tap(wrap)
+    
+    defactory = detap
+    
+    def wrap(self, wrapper):
+        '''
+        wrapper for outgoing things
+
+        @param wrapper: an iterator
+        '''
+        self._wrapper = wrapper
+        return self
+    
+    def unwrap(self):
+        '''clear current wrapper'''
+        self._wrapper = self._list
+        return self
 
     ###########################################################################
     ## things rotation ########################################################
         with self.ctx1():
             return self._append(thing)
 
-    def appendleft(self, thing):
+    def prepend(self, thing):
         '''
         append `thing` to left side of incoming things
 
         '''
         with self.ctx1():
             return self._appendleft(thing)
+        
+    appendleft = prepend
 
     ###########################################################################
     ## things extension #######################################################
         with self.ctx1():
             return self._xtend(things)
 
-    def extendleft(self, things):
+    def preextend(self, things):
         '''
         extend left side of incoming things with `things`
 
         '''
         with self.ctx1():
             return self._xtendleft(things)
+        
+    extendleft = preextend
 
     def outextend(self, things):
         '''
         # return to default context
         self.unswap()
         out, tell = self._split(self.outgoing)
-        list_ = self._list
-        out = self._next(out) if self._len(list_(tell)) == 1 else list_(out)
+        wrap = self._wrapper
+        out = self._next(out) if self._len(wrap(tell)) == 1 else wrap(out)
         # clear every last thing
         self.clear()
         return out
 
     def peek(self):
         '''results from read-only context'''
-        out = self._list(self._util)
+        out = self._wrapper(self._util)
         return out[0] if self._len(out) == 1 else out
 
     def results(self):
         # return to default context
         self.unswap()
         out, tell = self._split(self.outgoing)
-        list_ = self._list
-        out = self._next(out) if self._len(list_(tell)) == 1 else list_(out)
+        wrap = self._wrapper
+        out = self._next(out) if self._len(wrap(tell)) == 1 else wrap(out)
         # clear outgoing things
         self.outclear()
         return out

twoq/tests/auto/filtering.py

             [('age', 40), ('name', 'moe'), ('age', 50), ('name', 'larry'),
             ('age', 60), ('name', 'curly')],
         )
+        
+    def test_extract(self):
+        from inspect import isclass
+        class stooges:
+            name = 'moe'
+            age = 40
+        class stoog2: #@IgnorePep8
+            name = 'larry'
+            age = 50
+        class stoog3: #@IgnorePep8
+            name = 'curly'
+            age = 60
+            class stoog4: #@IgnorePep8
+                name = 'beastly'
+                age = 969
+        test = lambda x: not x.startswith('__')
+        value = self.qclass(
+            stooges, stoog2, stoog3
+        ).tap(test).alt(isclass).wrap(tuple).extract().detap().end(),
+        self.assertEqual(
+            value,
+            ((('age', 40), ('name', 'moe'), ('age', 50), ('name', 'larry'), ('age', 60), ('name', 'curly'), ('stoog4', (('age', 969), ('name', 'beastly')))),),
+            value,
+        )
 
     def test_deepmembers(self):
         class stooges:

twoq/tests/auto/mapping.py

 
 class AMapQMixin(ADelayQMixin, ARepeatQMixin):
 
-    def test_wrap(self):
+    def test_factory(self):
         from stuf import stuf
         self.assertDictEqual(
             self.qclass(
                 ('a', 1), ('b', 2), ('c', 3)
-            ).reup().wrap(stuf).map().end(),
+            ).reup().factory(stuf).map().end(),
             stuf(a=1, b=2, c=3),
         )
 

twoq/tests/man/filtering.py

             [('age', 40), ('name', 'moe'), ('age', 50), ('name', 'larry'),
             ('age', 60), ('name', 'curly')],
         )
+        
+    def test_extract(self):
+        from inspect import isclass
+        class stooges:
+            name = 'moe'
+            age = 40
+        class stoog2: #@IgnorePep8
+            name = 'larry'
+            age = 50
+        class stoog3: #@IgnorePep8
+            name = 'curly'
+            age = 60
+            class stoog4: #@IgnorePep8
+                name = 'beastly'
+                age = 969
+        self._true_true_false(
+            self.qclass(
+                stooges, stoog2, stoog3
+            ).tap(
+                lambda x: not x.startswith('__')
+            ).alt(isclass).wrap(tuple).extract().detap().sync(),
+            self.assertEqual,
+            (('age', 40), ('name', 'moe'), ('age', 50), ('name', 'larry'), ('age', 60), ('name', 'curly'), ('stoog4', (('age', 969), ('name', 'beastly')))),
+        )
 
     def test_deepmembers(self):
         class stooges:

twoq/tests/man/manning.py

         manq.sync()
         self.assertTrue(manq.balanced)
         if comp is not None:
-            expr(manq.value(), comp)
+            value = manq.value()
+            expr(value, comp, value)
         else:
             expr(manq.value())
         self.assertFalse(manq.balanced)

twoq/tests/man/mapping.py

 
 class MMapQMixin(MDelayQMixin, MRepeatQMixin):
 
-    def test_wrap(self):
+    def test_factory(self):
         from stuf import stuf
         thing = self.qclass(
             ('a', 1), ('b', 2), ('c', 3)
-        ).reup().wrap(stuf).map().shift().end()
+        ).reup().factory(stuf).map().shift().end()
         self.assertDictEqual(thing, stuf(a=1, b=2, c=3), thing)
 
     def test_each(self):