1- from ._helpers import AnalyzerHelpers , Log , ParsingHelpers , ReportingHelpers
1+ from ._helpers import AnalyzerHelpers , Log , ParsingHelpers , ReportingHelpers , flatten_nested_dictionary_values
22from ._parser import SwiftFile
3+ from dataclasses import dataclass
34from functional import seq
45from typing import Dict , List , Optional
56
@@ -191,31 +192,61 @@ def __is_name_contained_in_list(framework: 'Framework', frameworks: List['Framew
191192 .list ()) > 0
192193
193194
195+ @dataclass
194196class SyntheticData :
195- def __init__ (self , swift_file : Optional ['SwiftFile' ] = None ):
196- self .loc = 0 if swift_file is None else swift_file .loc
197- self .noc = 0 if swift_file is None else swift_file .n_of_comments
198- self .number_of_interfaces = 0 if swift_file is None else len (swift_file .interfaces )
199- self .number_of_concrete_data_structures = 0 if swift_file is None else \
200- len (swift_file .structs + swift_file .classes )
201- self .number_of_methods = 0 if swift_file is None else len (swift_file .methods )
202- self .number_of_tests = 0 if swift_file is None else len (swift_file .tests )
203-
204- def append_data (self , data : 'SyntheticData' ):
205- self .loc += data .loc
206- self .noc += data .noc
207- self .number_of_interfaces += data .number_of_interfaces
208- self .number_of_concrete_data_structures += data .number_of_concrete_data_structures
209- self .number_of_methods += data .number_of_methods
210- self .number_of_tests += data .number_of_tests
211-
212- def remove_data (self , data : 'SyntheticData' ):
213- self .loc -= data .loc
214- self .noc -= data .noc
215- self .number_of_interfaces -= data .number_of_interfaces
216- self .number_of_concrete_data_structures -= data .number_of_concrete_data_structures
217- self .number_of_methods -= data .number_of_methods
218- self .number_of_tests -= data .number_of_tests
197+ """
198+ Representation of synthetic code metric data
199+ """
200+ loc : int = 0
201+ noc : int = 0
202+ number_of_interfaces : int = 0
203+ number_of_concrete_data_structures : int = 0
204+ number_of_methods : int = 0
205+ number_of_tests : int = 0
206+
207+ @classmethod
208+ def from_swift_file (cls , swift_file : Optional ['SwiftFile' ] = None ) -> 'SyntheticData' :
209+ return SyntheticData (
210+ loc = 0 if swift_file is None else swift_file .loc ,
211+ noc = 0 if swift_file is None else swift_file .n_of_comments ,
212+ number_of_interfaces = 0 if swift_file is None else len (swift_file .interfaces ),
213+ number_of_concrete_data_structures = 0 if swift_file is None else \
214+ len (swift_file .structs + swift_file .classes ),
215+ number_of_methods = 0 if swift_file is None else len (swift_file .methods ),
216+ number_of_tests = 0 if swift_file is None else len (swift_file .tests )
217+ )
218+
219+ def __add__ (self , data ):
220+ """
221+ Implementation of the `+` operator
222+ :param data: An instance of SyntheticData
223+ :return: a new instance of SyntheticData
224+ """
225+ return SyntheticData (
226+ loc = self .loc + data .loc ,
227+ noc = self .noc + data .noc ,
228+ number_of_interfaces = self .number_of_interfaces + data .number_of_interfaces ,
229+ number_of_concrete_data_structures = self .number_of_concrete_data_structures
230+ + data .number_of_concrete_data_structures ,
231+ number_of_methods = self .number_of_methods + data .number_of_methods ,
232+ number_of_tests = self .number_of_tests + data .number_of_tests
233+ )
234+
235+ def __sub__ (self , data ):
236+ """
237+ Implementation of the `-` operator
238+ :param data: An instance of SyntheticData
239+ :return: a new instance of SyntheticData
240+ """
241+ return SyntheticData (
242+ loc = self .loc - data .loc ,
243+ noc = self .noc - data .noc ,
244+ number_of_interfaces = self .number_of_interfaces - data .number_of_interfaces ,
245+ number_of_concrete_data_structures = self .number_of_concrete_data_structures
246+ - data .number_of_concrete_data_structures ,
247+ number_of_methods = self .number_of_methods - data .number_of_methods ,
248+ number_of_tests = self .number_of_tests - data .number_of_tests
249+ )
219250
220251 @property
221252 def poc (self ) -> float :
@@ -234,30 +265,82 @@ def as_dict(self) -> Dict:
234265 }
235266
236267
268+ @dataclass ()
237269class FrameworkData (SyntheticData ):
238- def __init__ (self , swift_file : Optional ['SwiftFile' ] = None ):
239- super ().__init__ (swift_file )
240- self .n_o_i = 0 if swift_file is None else \
241- len ([imp for imp in swift_file .imports if imp not in AnalyzerHelpers .APPLE_FRAMEWORKS ])
270+ """
271+ Enriched synthetic data
272+ """
273+ n_o_i : int = 0
274+
275+ @classmethod
276+ def from_swift_file (cls , swift_file : Optional ['SwiftFile' ] = None ) -> 'FrameworkData' :
277+ sd = SyntheticData .from_swift_file (swift_file = swift_file )
278+ return FrameworkData .__from_sd (sd = sd ,
279+ n_o_i = 0 if swift_file is None else \
280+ len ([imp for imp in swift_file .imports if imp not in \
281+ AnalyzerHelpers .APPLE_FRAMEWORKS ]))
282+
283+ def __add__ (self , data ):
284+ """
285+ Implementation of the `+` operator
286+ :param data: An instance of FrameworkData
287+ :return: a new instance of FrameworkData
288+ """
289+ sd = self .__current_sd ().__add__ (data = data )
290+ return FrameworkData .__from_sd (sd = sd , n_o_i = self .n_o_i + data .n_o_i )
291+
292+ def __sub__ (self , data ):
293+ """
294+ Implementation of the `-` operator
295+ :param data: An instance of FrameworkData
296+ :return: a new instance of FrameworkData
297+ """
298+ sd = self .__current_sd ().__sub__ (data = data )
299+ return FrameworkData .__from_sd (sd = sd , n_o_i = self .n_o_i - data .n_o_i )
242300
243301 def append_framework (self , f : 'Framework' ):
244- super ().append_data (data = f .data )
302+ sd = f .data
303+ self .loc += sd .loc
304+ self .noc += sd .noc
305+ self .number_of_interfaces += sd .number_of_interfaces
306+ self .number_of_concrete_data_structures += sd .number_of_concrete_data_structures
307+ self .number_of_methods += sd .number_of_methods
308+ self .number_of_tests += sd .number_of_tests
245309 self .n_o_i += f .number_of_imports
246310
247- def remove_data (self , data : 'FrameworkData' ):
248- super ().remove_data (data = data )
249- self .n_o_i -= data .n_o_i
250-
251311 @property
252312 def as_dict (self ) -> Dict :
253313 return {** super ().as_dict , ** {"noi" : self .n_o_i }}
254314
315+ # Private
316+
317+ def __current_sd (self ) -> 'SyntheticData' :
318+ return SyntheticData (
319+ loc = self .loc ,
320+ noc = self .noc ,
321+ number_of_interfaces = self .number_of_interfaces ,
322+ number_of_concrete_data_structures = self .number_of_concrete_data_structures ,
323+ number_of_methods = self .number_of_methods ,
324+ number_of_tests = self .number_of_tests
325+ )
326+
327+ @classmethod
328+ def __from_sd (cls , sd : 'SyntheticData' , n_o_i : int ) -> 'FrameworkData' :
329+ return FrameworkData (
330+ loc = sd .loc ,
331+ noc = sd .noc ,
332+ number_of_interfaces = sd .number_of_interfaces ,
333+ number_of_concrete_data_structures = sd .number_of_concrete_data_structures ,
334+ number_of_methods = sd .number_of_methods ,
335+ number_of_tests = sd .number_of_tests ,
336+ n_o_i = n_o_i
337+ )
338+
255339
256340class Framework :
257341 def __init__ (self , name : str , is_test_framework : bool = False ):
258342 self .name = name
259- self .number_of_files = 0
260- self .data = SyntheticData ()
343+ self .raw_files = {}
261344 self .__total_imports = {}
262345 self .is_test_framework = is_test_framework
263346
@@ -276,6 +359,25 @@ def append_import(self, framework_import: 'Framework'):
276359 else :
277360 self .__total_imports [framework_import ] += 1
278361
362+ @property
363+ def data (self ) -> SyntheticData :
364+ """
365+ The metrics data describing the framework
366+ :return: an instance of SyntheticData
367+ """
368+ if self .number_of_files == 0 :
369+ return SyntheticData ()
370+ return seq ([SyntheticData .from_swift_file (swift_file = sf ) for sf in self .__raw_files_data ()]) \
371+ .reduce (lambda sd1 , sd2 : sd1 + sd2 )
372+
373+ @property
374+ def number_of_files (self ) -> int :
375+ """
376+ Number of files in the framework
377+ :return: The total number of files in this framework (int)
378+ """
379+ return len (self .__raw_files_data ())
380+
279381 @property
280382 def imports (self ) -> Dict [str , int ]:
281383 """
@@ -311,12 +413,17 @@ def compact_name_description(self) -> str:
311413 def __filtered_imports (items : 'ItemsView' ) -> Dict [str , int ]:
312414 return seq (items ).filter (lambda f : f [0 ].name not in AnalyzerHelpers .APPLE_FRAMEWORKS ).dict ()
313415
416+ # Private
417+
418+ def __raw_files_data (self ) -> List ['SwiftFile' ]:
419+ return list (flatten_nested_dictionary_values (self .raw_files ))
420+
314421
422+ @dataclass
315423class Dependency :
316- def __init__ (self , name : str , dependent_framework : str , number_of_imports : int = 0 ):
317- self .name = name
318- self .dependent_framework = dependent_framework
319- self .number_of_imports = number_of_imports
424+ name : str
425+ dependent_framework : str
426+ number_of_imports : int = 0
320427
321428 def __eq__ (self , other ):
322429 return (self .name == other .name ) and \
@@ -333,4 +440,3 @@ def compact_repr(self) -> str:
333440 @property
334441 def relationship (self ) -> str :
335442 return f'{ self .name } > { self .dependent_framework } '
336-
0 commit comments