Package osh :: Package command :: Module squish
[frames] | no frames]

Source Code for Module osh.command.squish

  1  # osh 
  2  # Copyright (C) 2005 Jack Orenstein <jao@geophile.com> 
  3  # 
  4  # This program is free software; you can redistribute it and/or modify 
  5  # it under the terms of the GNU General Public License as published by 
  6  # the Free Software Foundation; either version 2 of the License, or 
  7  # (at your option) any later version. 
  8  # 
  9  # This program is distributed in the hope that it will be useful, 
 10  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 11  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 12  # GNU General Public License for more details. 
 13  # 
 14  # You should have received a copy of the GNU General Public License 
 15  # along with this program; if not, write to the Free Software 
 16  # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
 17   
 18  """C{squish [SQUISH_OP ...]} 
 19   
 20  Each input sequence is reduced to a single value, using C{SQUISH_OP} 
 21  to combine the values. C{SQUISH_OP} is a binary function that can be 
 22  used for reduction, e.g. C{+}, C{*}, C{max}, C{min}, but not C{-} or 
 23  C{/}. 
 24   
 25  B{Example}: If one of the inputs is the list C{[1, 2, 3, 4]}, then:: 
 26   
 27      squish + 
 28   
 29  will generate C{10} (= C{1 + 2 + 3 + 4}). 
 30   
 31  The result is exactly equivalent to what would be produced by using 
 32  the Python function C{map}, e.g.:: 
 33   
 34      map 'list: squish(lambda a, b: a + b, list)' 
 35   
 36  If input sequences contain nested sequences, then multiple C{SQUISH_OP}s 
 37  can be provided, to do multiple reductions at once. For example, if 
 38  one input sequence is C{[[10, 20, 30], [1, 100, 1000], [111, 222, 333]]} 
 39  then:: 
 40   
 41      squish + max min 
 42   
 43  will produce C{[122, 222, 30]}. C{122} is C{10 + 1 + 111}, C{222} is C{max(20, 100, 222)}, and 
 44  C{30} is C{min(30, 1000, 333)}. 
 45   
 46  If no C{SQUISH_OP} is provided, then C{+} is assumed. 
 47  """ 
 48   
 49  import types 
 50   
 51  import osh.core 
 52  from osh.function import _Function 
 53   
 54  # CLI 
55 -def _squish():
56 return _Squish()
57 58 # API
59 -def squish(*squish_ops):
60 """Each input sequence is reduced to a single value. Elements 61 of the input sequence are combined using a C{squish_op}, a binary function 62 that can be used for reduction, i.e. a binary associative function such as addition, 63 but not subtraction, (because x + y = y + x, but x - y != y - x). 64 If input sequences contain nested sequences, then multiple C{squish_op}s 65 can be provided, to do multiple reductions at once. The squish_op can be a function-valued 66 expression, a string function expression (e.g. C{'x, y: x + y'}), or a string describing 67 a binary associative operator, specifically one of: C{+, *, ^, &, |, and, or}. 68 """ 69 return _Squish().process_args(*squish_ops)
70
71 -class _Squish(osh.core.Op):
72 73 _squisher = None 74 75 76 # object interface 77
78 - def __init__(self):
79 osh.core.Op.__init__(self, '', (0, None))
80 81 82 # BaseOp interface 83
84 - def doc(self):
85 return __doc__
86
87 - def setup(self):
88 args = self.args() 89 squish_ops = [] 90 while args.has_next(): 91 arg = args.next() 92 if type(arg) in [types.FunctionType, types.BuiltinFunctionType]: 93 op = _Function(arg) 94 elif isinstance(arg, str): 95 f = operator_to_function(arg) 96 if f: 97 op = _Function(f) 98 else: 99 op = _Function(arg) 100 squish_ops.append(op) 101 if len(squish_ops) == 0: 102 squish_ops.append(_Function(lambda x, y: x + y)) 103 if len(squish_ops) == 1: 104 self._squisher = _object_squisher(squish_ops[0]) 105 else: 106 self._squisher = _sequence_squisher(squish_ops)
107
108 - def receive(self, object):
109 squished = self._squisher(object) 110 self.send(squished)
111
112 -def _object_squisher(op):
113 return lambda input: reduce(op, input)
114
115 -def _sequence_squisher(ops):
116 def all_ops(x, y): 117 return [ops[i](x[i], y[i]) for i in xrange(len(ops))]
118 return lambda input: reduce(all_ops, input) 119
120 -def operator_to_function(op):
121 if op == '+': 122 f = lambda x, y: x + y 123 elif op == '*': 124 f = lambda x, y: x * y 125 elif op == '^': 126 f = lambda x, y: x ^ y 127 elif op == '&': 128 f = lambda x, y: x & y 129 elif op == '|': 130 f = lambda x, y: x | y 131 elif op == 'and': 132 f = lambda x, y: x and y 133 elif op == 'or': 134 f = lambda x, y: x or y 135 elif op == 'max': 136 f = lambda x, y: max(x, y) 137 elif op == 'min': 138 f = lambda x, y: min(x, y) 139 else: 140 f = None 141 return f
142