Conditions | 18 |
Total Lines | 73 |
Code Lines | 61 |
Lines | 0 |
Ratio | 0 % |
Changes | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like generate_protocol_python.CodeGenerator.generate_struct_code() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
1 | |||
100 | def generate_struct_code(self, obj): |
||
101 | self.write('') |
||
102 | self.write('') |
||
103 | self.iidx = 0 |
||
104 | self.write(f'class {obj.name}(FrozenClass):') |
||
105 | self.iidx += 1 |
||
106 | self.write('"""') |
||
107 | if obj.doc: |
||
108 | self.write(obj.doc) |
||
109 | self.write("") |
||
110 | for field in obj.fields: |
||
111 | self.write(f':ivar {field.name}:') |
||
112 | self.write(f':vartype {field.name}: {field.uatype}') |
||
113 | self.write('"""') |
||
114 | |||
115 | self.write('') |
||
116 | switch_written = False |
||
117 | for field in obj.fields: |
||
118 | if field.switchfield is not None: |
||
119 | if not switch_written: |
||
120 | self.write('ua_switches = {') |
||
121 | switch_written = True |
||
122 | |||
123 | bit = obj.bits[field.switchfield] |
||
124 | self.write(f" '{field.name}': ('{bit.container}', {bit.idx}),") |
||
125 | #if field.switchvalue is not None: Not sure we need to handle that one |
||
126 | if switch_written: |
||
127 | self.write(" }") |
||
128 | self.write("ua_types = [") |
||
129 | for field in obj.fields: |
||
130 | prefix = "ListOf" if field.length else "" |
||
131 | uatype = prefix + field.uatype |
||
132 | if uatype == "ListOfChar": |
||
133 | uatype = "String" |
||
134 | self.write(f" ('{field.name}', '{uatype}'),") |
||
135 | self.write(" ]") |
||
136 | self.write("") |
||
137 | |||
138 | self.write("def __init__(self):") |
||
139 | self.iidx += 1 |
||
140 | |||
141 | # hack extension object stuff |
||
142 | extobj_hack = False |
||
143 | if "BodyLength" in [f.name for f in obj.fields]: |
||
144 | extobj_hack = True |
||
145 | |||
146 | for field in obj.fields: |
||
147 | if extobj_hack and field.name == "Encoding": |
||
148 | self.write("self.Encoding = 1") |
||
149 | elif field.uatype == obj.name: # help!!! selv referencing class |
||
150 | self.write("self.{} = None".format(field.name)) |
||
151 | elif not obj.name in ("ExtensionObject") and field.name == "TypeId": # and ( obj.name.endswith("Request") or obj.name.endswith("Response")): |
||
152 | self.write(f"self.TypeId = FourByteNodeId(ObjectIds.{obj.name}_Encoding_DefaultBinary)") |
||
153 | else: |
||
154 | self.write(f"self.{field.name} = {'[]' if field.length else self.get_default_value(field)}") |
||
155 | self.write("self._freeze = True") |
||
156 | self.iidx = 1 |
||
157 | |||
158 | #__str__ |
||
159 | self.write("") |
||
160 | self.write("def __str__(self):") |
||
161 | self.iidx += 1 |
||
162 | tmp = [f"{f.name}:{{self.{f.name}}}" for f in obj.fields] |
||
163 | tmp = ", ".join(tmp) |
||
164 | if tmp: |
||
165 | self.write(f"return f'{obj.name}({tmp})'") |
||
166 | else: |
||
167 | self.write(f"return '{obj.name}()'") |
||
168 | self.iidx -= 1 |
||
169 | self.write("") |
||
170 | self.write("__repr__ = __str__") |
||
171 | |||
172 | self.iix = 0 |
||
173 | |||
242 |