diff --git a/examples/crapper.edn b/examples/crapper.edn index 9c44219..006cb88 100644 --- a/examples/crapper.edn +++ b/examples/crapper.edn @@ -185,7 +185,8 @@ {:name "declared_namespace", :text "declared_namespace"} {:name "namespace_from_path", :text "namespace_from_path"} {:name "functions_in_source", :text "functions_in_source"} - {:name "Clojure", :text "Clojure"}], + {:name "Clojure", :text "Clojure"} + {:name "ClojureFactory", :text "ClojureFactory"}], :level 1, :lang :python, :id :languages.clojure} @@ -195,7 +196,8 @@ :ops [{:name "package_namespace", :text "package_namespace"} {:name "functions_in_source", :text "functions_in_source"} - {:name "Go", :text "Go"}], + {:name "Go", :text "Go"} + {:name "GoFactory", :text "GoFactory"}], :level 1, :lang :python, :id :languages.golang} @@ -204,14 +206,19 @@ :file "src/crapper/languages/java.py", :ops [{:name "functions_in_source", :text "functions_in_source"} - {:name "Java", :text "Java"}], + {:name "Java", :text "Java"} + {:name "JavaFactory", :text "JavaFactory"}], :level 1, :lang :python, :id :languages.java} {:ns "crapper.languages.language", :name "Language", :file "src/crapper/languages/language.py", - :ops [{:name "Language", :text "Language"} {:name "Unknown", :text "Unknown"}], + :ops + [{:name "Language", :text "Language"} + {:name "Unknown", :text "Unknown"} + {:name "LanguageFactory", :text "LanguageFactory"} + {:name "UnknownFactory", :text "UnknownFactory"}], :level 1, :lang :python, :id :languages.language} @@ -220,7 +227,8 @@ :file "src/crapper/languages/python.py", :ops [{:name "functions_in_source", :text "functions_in_source"} - {:name "Python", :text "Python"}], + {:name "Python", :text "Python"} + {:name "PythonFactory", :text "PythonFactory"}], :level 1, :lang :python, :id :languages.python} @@ -229,7 +237,8 @@ :file "src/crapper/languages/rust.py", :ops [{:name "functions_in_source", :text "functions_in_source"} - {:name "Rust", :text "Rust"}], + {:name "Rust", :text "Rust"} + {:name "RustFactory", :text "RustFactory"}], :level 1, :lang :python, :id :languages.rust} @@ -254,7 +263,8 @@ :file "src/crapper/languages/typescript.py", :ops [{:name "functions_in_source", :text "functions_in_source"} - {:name "TypeScript", :text "TypeScript"}], + {:name "TypeScript", :text "TypeScript"} + {:name "TypeScriptFactory", :text "TypeScriptFactory"}], :level 1, :lang :python, :id :languages.typescript} diff --git a/src/crapper/languages/__init__.py b/src/crapper/languages/__init__.py index f9725ed..ea7383e 100644 --- a/src/crapper/languages/__init__.py +++ b/src/crapper/languages/__init__.py @@ -1,27 +1,27 @@ """Per-language function extraction.""" -from crapper.languages.clojure import Clojure -from crapper.languages.golang import Go -from crapper.languages.java import Java -from crapper.languages.language import Unknown -from crapper.languages.python import Python -from crapper.languages.rust import Rust -from crapper.languages.typescript import TypeScript +from crapper.languages.clojure import ClojureFactory +from crapper.languages.golang import GoFactory +from crapper.languages.java import JavaFactory +from crapper.languages.language import LanguageFactory, UnknownFactory +from crapper.languages.python import PythonFactory +from crapper.languages.rust import RustFactory +from crapper.languages.typescript import TypeScriptFactory from crapper.model import Function -_LANGUAGES = { - "clojure": Clojure(), - "java": Java(), - "go": Go(), - "typescript": TypeScript(), - "python": Python(), - "rust": Rust(), +_FACTORIES: dict[str, LanguageFactory] = { + "clojure": ClojureFactory(), + "java": JavaFactory(), + "go": GoFactory(), + "typescript": TypeScriptFactory(), + "python": PythonFactory(), + "rust": RustFactory(), } -_UNKNOWN = Unknown() +_UNKNOWN = UnknownFactory() def functions_in_file( language: str, source: str, path: str, project_root: str ) -> list[Function]: - chosen = _LANGUAGES.get(language, _UNKNOWN) - return chosen.functions(source, path, project_root) + factory = _FACTORIES.get(language, _UNKNOWN) + return factory.create().functions(source, path, project_root) diff --git a/src/crapper/languages/clojure.py b/src/crapper/languages/clojure.py index 1ee6f33..b43304f 100644 --- a/src/crapper/languages/clojure.py +++ b/src/crapper/languages/clojure.py @@ -7,7 +7,7 @@ variants, `and`, `or`, `loop`, `catch`, and each clause of `cond`, `condp`, import re -from crapper.languages.language import Language +from crapper.languages.language import Language, LanguageFactory from crapper.model import Function _DECISION = re.compile( @@ -291,3 +291,8 @@ def functions_in_source( class Clojure(Language): def functions(self, source: str, path: str, project_root: str) -> list[Function]: return functions_in_source(source, path, project_root) + + +class ClojureFactory(LanguageFactory): + def create(self) -> Language: + return Clojure() diff --git a/src/crapper/languages/golang.py b/src/crapper/languages/golang.py index ae43d3f..ef8349b 100644 --- a/src/crapper/languages/golang.py +++ b/src/crapper/languages/golang.py @@ -19,7 +19,7 @@ from crapper.languages.treesitter import ( parse, start_line, ) -from crapper.languages.language import Language +from crapper.languages.language import Language, LanguageFactory from crapper.model import Function _DECISIONS = { @@ -155,3 +155,8 @@ def functions_in_source( class Go(Language): def functions(self, source: str, path: str, project_root: str) -> list[Function]: return functions_in_source(source, path, project_root) + + +class GoFactory(LanguageFactory): + def create(self) -> Language: + return Go() diff --git a/src/crapper/languages/java.py b/src/crapper/languages/java.py index 0b8e7e7..c512f25 100644 --- a/src/crapper/languages/java.py +++ b/src/crapper/languages/java.py @@ -17,7 +17,7 @@ from crapper.languages.treesitter import ( parse, start_line, ) -from crapper.languages.language import Language +from crapper.languages.language import Language, LanguageFactory from crapper.model import Function _PACKAGE = re.compile(r"(?m)^\s*package\s+([a-zA-Z_][\w.]*)\s*;") @@ -120,3 +120,8 @@ def functions_in_source(source: str, path: str) -> list[Function]: class Java(Language): def functions(self, source: str, path: str, project_root: str) -> list[Function]: return functions_in_source(source, path) + + +class JavaFactory(LanguageFactory): + def create(self) -> Language: + return Java() diff --git a/src/crapper/languages/language.py b/src/crapper/languages/language.py index f57b49c..093b3af 100644 --- a/src/crapper/languages/language.py +++ b/src/crapper/languages/language.py @@ -1,4 +1,4 @@ -"""The operation every language implements.""" +"""The language operation, and the factories that create language instances.""" from abc import ABC, abstractmethod @@ -14,3 +14,14 @@ class Language(ABC): class Unknown(Language): def functions(self, source: str, path: str, project_root: str) -> list[Function]: return [] + + +class LanguageFactory(ABC): + @abstractmethod + def create(self) -> Language: + """A language instance ready to read source files.""" + + +class UnknownFactory(LanguageFactory): + def create(self) -> Language: + return Unknown() diff --git a/src/crapper/languages/python.py b/src/crapper/languages/python.py index 793fd31..6386a33 100644 --- a/src/crapper/languages/python.py +++ b/src/crapper/languages/python.py @@ -16,7 +16,7 @@ from crapper.languages.treesitter import ( parse, start_line, ) -from crapper.languages.language import Language +from crapper.languages.language import Language, LanguageFactory from crapper.model import Function _DECISIONS = { @@ -137,3 +137,8 @@ def functions_in_source( class Python(Language): def functions(self, source: str, path: str, project_root: str) -> list[Function]: return functions_in_source(source, path, project_root) + + +class PythonFactory(LanguageFactory): + def create(self) -> Language: + return Python() diff --git a/src/crapper/languages/rust.py b/src/crapper/languages/rust.py index f368b76..3c802c6 100644 --- a/src/crapper/languages/rust.py +++ b/src/crapper/languages/rust.py @@ -20,7 +20,7 @@ from crapper.languages.treesitter import ( parse, start_line, ) -from crapper.languages.language import Language +from crapper.languages.language import Language, LanguageFactory from crapper.model import Function _DECISIONS = { @@ -192,3 +192,8 @@ def functions_in_source( class Rust(Language): def functions(self, source: str, path: str, project_root: str) -> list[Function]: return functions_in_source(source, path, project_root) + + +class RustFactory(LanguageFactory): + def create(self) -> Language: + return Rust() diff --git a/src/crapper/languages/typescript.py b/src/crapper/languages/typescript.py index 4daf0f0..67f1699 100644 --- a/src/crapper/languages/typescript.py +++ b/src/crapper/languages/typescript.py @@ -17,7 +17,7 @@ from crapper.languages.treesitter import ( parse, start_line, ) -from crapper.languages.language import Language +from crapper.languages.language import Language, LanguageFactory from crapper.model import Function _DECISIONS = { @@ -184,3 +184,8 @@ def functions_in_source( class TypeScript(Language): def functions(self, source: str, path: str, project_root: str) -> list[Function]: return functions_in_source(source, path, project_root) + + +class TypeScriptFactory(LanguageFactory): + def create(self) -> Language: + return TypeScript()