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

Source Code for Module osh.command.expand

  1  # osh 
  2  # Copyright (C) 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{expand [POSITION]} 
 19   
 20  Receives a stream of sequences as input. If C{POSITION} is omitted, then 
 21  each item of the sequence is generated as a separate 1-tuple in the 
 22  output stream. 
 23   
 24  B{Example}: If the input contains these sequences:: 
 25   
 26      ('a', 'b') 
 27      ('c', 'd') 
 28   
 29  then C{expand} generates this output:: 
 30      ('a',) 
 31      ('b',) 
 32      ('c',) 
 33      ('d',) 
 34   
 35  If C{POSITION} is specified, then each input sequence is used to generate 
 36  zero or more output sequences. In each output sequence, the item at the 
 37  selected position is replaced by one component of the selected object. 
 38   
 39  The types that can be expanded are C{list}, C{tuple}, C{generator}, 
 40  and C{osh.file.File}. Expansion of a C{osh.file.File} 
 41  yields each line of the named file. 
 42   
 43  B{Example}: If the input contains these sequences:: 
 44   
 45      ('a', [1, 2, 3], 'x') 
 46      ('b', [4, 5], 'y') 
 47      ('c', [], 'z') 
 48   
 49  then C{expand 1} generates this output:: 
 50   
 51      ('a', 1, 'x') 
 52      ('a', 2, 'x') 
 53      ('a', 3, 'x') 
 54      ('b', 4, 'y') 
 55      ('b', 5, 'y') 
 56   
 57  Note that an empty nested sequence results in no output, (as for 
 58  C{('c', [], 'z')}.) 
 59  """ 
 60   
 61  import types 
 62   
 63  import osh.core 
 64  import osh.file 
 65   
 66  # CLI 
67 -def _expand():
68 return _Expand()
69 70 # API
71 -def expand(position = None):
72 """Flattens an input sequence by generating output sequences in which an interior element 73 is expanded. If C{position} is omitted, then each element of the input sequence is generated 74 as a separate 1-tuples. If C{position} is specified, then the item at the given position 75 is expanded. If the element being expanded is a string, then the string is interpreted 76 as a filename, and the expansion yields each line of the file in turn. 77 """ 78 args = [] 79 if position is not None: 80 args.append(position) 81 return _Expand().process_args(*args)
82
83 -class _Expand(osh.core.Op):
84 85 _expander = None 86 87 88 # object interface 89
90 - def __init__(self):
91 osh.core.Op.__init__(self, None, (0, 1))
92 93 94 # BaseOp interface 95
96 - def doc(self):
97 return __doc__
98
99 - def setup(self):
100 args = self.args() 101 position = args.next_int() 102 if position is not None and args.has_next(): 103 self.usage() 104 if position is None: 105 self._expander = _SequenceExpander(self) 106 else: 107 self._expander = _ComponentExpander(self, position)
108
109 - def receive(self, sequence):
110 self._expander.expand(sequence)
111
112 -class _Expander(object):
113 114 _command = None 115
116 - def __init__(self, command):
117 self._command = command
118
119 - def expand(self, sequence):
120 assert False
121
122 - def contents(self, object):
123 contents_generator = self._expand_as_file(object) 124 if not contents_generator: 125 contents_generator = self._expand_as_sequence(object) 126 if not contents_generator: 127 raise _NotExpandableException(object) 128 return contents_generator
129
130 - def _expand_as_file(self, object):
131 assert False
132
133 - def _expand_as_sequence(self, object):
134 if (isinstance(object, tuple) or 135 isinstance(object, list) or 136 isinstance(object, types.GeneratorType)): 137 return self._expand_sequence(object) 138 else: 139 return None
140
141 - def _expand_file(self, f):
142 if isinstance(f, osh.file.File): 143 filename = f.abspath 144 else: 145 filename = f 146 file = open(filename, 'r') 147 eof = False 148 while not eof: 149 line = file.readline() 150 if line: 151 if line.endswith('\n'): 152 line = line[:-1] 153 yield line 154 else: 155 eof = True 156 file.close()
157
158 - def _expand_sequence(self, sequence):
159 for object in sequence: 160 yield object
161
162 -class _SequenceExpander(_Expander):
163
164 - def __init__(self, command):
165 _Expander.__init__(self, command)
166
167 - def expand(self, sequence):
168 for object in self.contents(sequence): 169 self._command.send(object)
170
171 - def _expand_as_file(self, object):
172 # Expand as file if object is a sequence of len 1, 173 # containing a File. 174 if ((isinstance(object, tuple) or isinstance(object, list)) and len(object) == 1): 175 object = object[0] 176 if isinstance(object, osh.file.File): 177 return self._expand_file(object) 178 else: 179 return None
180
181 -class _ComponentExpander(_Expander):
182 183 _position = None 184
185 - def __init__(self, command, position):
186 _Expander.__init__(self, command) 187 self._position = position
188
189 - def expand(self, sequence):
190 pre = sequence[:self._position] 191 if self._position == -1: 192 post = tuple() 193 else: 194 post = sequence[(self._position + 1):] 195 contents = self.contents(sequence[self._position]) 196 for object in contents: 197 output = pre + (object,) + post 198 self._command.send(output)
199
200 - def _expand_as_file(self, sequence):
201 # Expand as file if item at position is a File. 202 if isinstance(sequence, osh.file.File): 203 return self._expand_file(sequence) 204 else: 205 return None
206
207 -class _NotExpandableException(Exception):
208 209 _object = None 210
211 - def __init__(self, object):
212 self._object = object
213
214 - def __str__(self):
215 return 'Object of type %s cannot be expanded: %s' % (type(self._object), self._object)
216