Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(84)

Side by Side Diff: tools/telemetry/third_party/rope/rope/refactor/encapsulate_field.py

Issue 1132103009: Example of refactoring using rope library. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 from rope.base import evaluate
2 from rope.base import exceptions
3 from rope.base import libutils
4 from rope.base import pynames
5 from rope.base import taskhandle
6 from rope.base import utils
7 from rope.base import worder
8 from rope.base.change import ChangeSet, ChangeContents
9 from rope.refactor import sourceutils, occurrences
10
11
12 class EncapsulateField(object):
13
14 def __init__(self, project, resource, offset):
15 self.project = project
16 self.name = worder.get_name_at(resource, offset)
17 this_pymodule = self.project.get_pymodule(resource)
18 self.pyname = evaluate.eval_location(this_pymodule, offset)
19 if not self._is_an_attribute(self.pyname):
20 raise exceptions.RefactoringError(
21 'Encapsulate field should be performed on class attributes.')
22 self.resource = self.pyname.get_definition_location()[0].get_resource()
23
24 def get_changes(self, getter=None, setter=None, resources=None,
25 task_handle=taskhandle.NullTaskHandle()):
26 """Get the changes this refactoring makes
27
28 If `getter` is not `None`, that will be the name of the
29 getter, otherwise ``get_${field_name}`` will be used. The
30 same is true for `setter` and if it is None set_${field_name} is
31 used.
32
33 `resources` can be a list of `rope.base.resource.File`\s that
34 the refactoring should be applied on; if `None` all python
35 files in the project are searched.
36
37 """
38 if resources is None:
39 resources = self.project.get_python_files()
40 changes = ChangeSet('Encapsulate field <%s>' % self.name)
41 job_set = task_handle.create_jobset('Collecting Changes',
42 len(resources))
43 if getter is None:
44 getter = 'get_' + self.name
45 if setter is None:
46 setter = 'set_' + self.name
47 renamer = GetterSetterRenameInModule(
48 self.project, self.name, self.pyname, getter, setter)
49 for file in resources:
50 job_set.started_job(file.path)
51 if file == self.resource:
52 result = self._change_holding_module(changes, renamer,
53 getter, setter)
54 changes.add_change(ChangeContents(self.resource, result))
55 else:
56 result = renamer.get_changed_module(file)
57 if result is not None:
58 changes.add_change(ChangeContents(file, result))
59 job_set.finished_job()
60 return changes
61
62 def get_field_name(self):
63 """Get the name of the field to be encapsulated"""
64 return self.name
65
66 def _is_an_attribute(self, pyname):
67 if pyname is not None and isinstance(pyname, pynames.AssignedName):
68 pymodule, lineno = self.pyname.get_definition_location()
69 scope = pymodule.get_scope().\
70 get_inner_scope_for_line(lineno)
71 if scope.get_kind() == 'Class':
72 return pyname in scope.get_names().values()
73 parent = scope.parent
74 if parent is not None and parent.get_kind() == 'Class':
75 return pyname in parent.get_names().values()
76 return False
77
78 def _get_defining_class_scope(self):
79 defining_scope = self._get_defining_scope()
80 if defining_scope.get_kind() == 'Function':
81 defining_scope = defining_scope.parent
82 return defining_scope
83
84 def _get_defining_scope(self):
85 pymodule, line = self.pyname.get_definition_location()
86 return pymodule.get_scope().get_inner_scope_for_line(line)
87
88 def _change_holding_module(self, changes, renamer, getter, setter):
89 pymodule = self.project.get_pymodule(self.resource)
90 class_scope = self._get_defining_class_scope()
91 defining_object = self._get_defining_scope().pyobject
92 start, end = sourceutils.get_body_region(defining_object)
93
94 new_source = renamer.get_changed_module(pymodule=pymodule,
95 skip_start=start, skip_end=end)
96 if new_source is not None:
97 pymodule = libutils.get_string_module(
98 self.project, new_source, self.resource)
99 class_scope = pymodule.get_scope().\
100 get_inner_scope_for_line(class_scope.get_start())
101 indents = sourceutils.get_indent(self.project) * ' '
102 getter = 'def %s(self):\n%sreturn self.%s' % \
103 (getter, indents, self.name)
104 setter = 'def %s(self, value):\n%sself.%s = value' % \
105 (setter, indents, self.name)
106 new_source = sourceutils.add_methods(pymodule, class_scope,
107 [getter, setter])
108 return new_source
109
110
111 class GetterSetterRenameInModule(object):
112
113 def __init__(self, project, name, pyname, getter, setter):
114 self.project = project
115 self.name = name
116 self.finder = occurrences.create_finder(project, name, pyname)
117 self.getter = getter
118 self.setter = setter
119
120 def get_changed_module(self, resource=None, pymodule=None,
121 skip_start=0, skip_end=0):
122 change_finder = _FindChangesForModule(self, resource, pymodule,
123 skip_start, skip_end)
124 return change_finder.get_changed_module()
125
126
127 class _FindChangesForModule(object):
128
129 def __init__(self, finder, resource, pymodule, skip_start, skip_end):
130 self.project = finder.project
131 self.finder = finder.finder
132 self.getter = finder.getter
133 self.setter = finder.setter
134 self.resource = resource
135 self.pymodule = pymodule
136 self.last_modified = 0
137 self.last_set = None
138 self.set_index = None
139 self.skip_start = skip_start
140 self.skip_end = skip_end
141
142 def get_changed_module(self):
143 result = []
144 for occurrence in self.finder.find_occurrences(self.resource,
145 self.pymodule):
146 start, end = occurrence.get_word_range()
147 if self.skip_start <= start < self.skip_end:
148 continue
149 self._manage_writes(start, result)
150 result.append(self.source[self.last_modified:start])
151 if self._is_assigned_in_a_tuple_assignment(occurrence):
152 raise exceptions.RefactoringError(
153 'Cannot handle tuple assignments in encapsulate field.')
154 if occurrence.is_written():
155 assignment_type = self.worder.get_assignment_type(start)
156 if assignment_type == '=':
157 result.append(self.setter + '(')
158 else:
159 var_name = self.source[occurrence.get_primary_range()[0]:
160 start] + self.getter + '()'
161 result.append(self.setter + '(' + var_name
162 + ' %s ' % assignment_type[:-1])
163 current_line = self.lines.get_line_number(start)
164 start_line, end_line = self.pymodule.logical_lines.\
165 logical_line_in(current_line)
166 self.last_set = self.lines.get_line_end(end_line)
167 end = self.source.index('=', end) + 1
168 self.set_index = len(result)
169 else:
170 result.append(self.getter + '()')
171 self.last_modified = end
172 if self.last_modified != 0:
173 self._manage_writes(len(self.source), result)
174 result.append(self.source[self.last_modified:])
175 return ''.join(result)
176 return None
177
178 def _manage_writes(self, offset, result):
179 if self.last_set is not None and self.last_set <= offset:
180 result.append(self.source[self.last_modified:self.last_set])
181 set_value = ''.join(result[self.set_index:]).strip()
182 del result[self.set_index:]
183 result.append(set_value + ')')
184 self.last_modified = self.last_set
185 self.last_set = None
186
187 def _is_assigned_in_a_tuple_assignment(self, occurance):
188 offset = occurance.get_word_range()[0]
189 return self.worder.is_assigned_in_a_tuple_assignment(offset)
190
191 @property
192 @utils.saveit
193 def source(self):
194 if self.resource is not None:
195 return self.resource.read()
196 else:
197 return self.pymodule.source_code
198
199 @property
200 @utils.saveit
201 def lines(self):
202 if self.pymodule is None:
203 self.pymodule = self.project.get_pymodule(self.resource)
204 return self.pymodule.lines
205
206 @property
207 @utils.saveit
208 def worder(self):
209 return worder.Worder(self.source)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698