model_view: introduce views to model based on model visitor
authorAlexandre Terrasa <alexandre@moz-code.org>
Tue, 15 Dec 2015 23:22:55 +0000 (18:22 -0500)
committerAlexandre Terrasa <alexandre@moz-code.org>
Fri, 18 Dec 2015 05:13:52 +0000 (00:13 -0500)
Signed-off-by: Alexandre Terrasa <alexandre@moz-code.org>

src/model/model_views.nit [new file with mode: 0644]

diff --git a/src/model/model_views.nit b/src/model/model_views.nit
new file mode 100644 (file)
index 0000000..3a88f45
--- /dev/null
@@ -0,0 +1,265 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+module model_views
+
+import model_visitor
+
+# Provide a configurable view to a model.
+#
+# This can be useful when you need to filter some mentities from a model
+# like private or fictive.
+#
+# TODO doc usage
+class ModelView
+       super ModelVisitor
+
+       # The model to view through `self`.
+       var model: Model
+
+       # MPackages visible through `self`.
+       var mpackages: Set[MPackage] is lazy do
+               var mpackages = new HashSet[MPackage]
+               for mpackage in model.mpackages do
+                       if not accept_mentity(mpackage) then continue
+                       mpackages.add mpackage
+               end
+               return mpackages
+       end
+
+       # MGroups visible through `self`.
+       var mgroups: Set[MGroup] is lazy do
+               var mgroups = new HashSet[MGroup]
+               for mpackage in mpackages do
+                       for mgroup in mpackage.mgroups do
+                               if not accept_mentity(mgroup) then continue
+                               mgroups.add mgroup
+                       end
+               end
+               return mgroups
+       end
+
+       # MModules visible through `self`.
+       var mmodules: Set[MModule] is lazy do
+               var mmodules = new HashSet[MModule]
+               for mmodule in model.mmodules do
+                       if not accept_mentity(mmodule) then continue
+                       mmodules.add mmodule
+               end
+               return mmodules
+       end
+
+       # MClasses visible through `self`.
+       var mclasses: Set[MClass] is lazy do
+               var mclasses = new HashSet[MClass]
+               for mclass in model.mclasses do
+                       if not accept_mentity(mclass) then continue
+                       mclasses.add mclass
+               end
+               return mclasses
+       end
+
+       # MClassDefs visible through `self`.
+       var mclassdefs: Set[MClassDef] is lazy do
+               var mclassdefs = new HashSet[MClassDef]
+               for mclass in mclasses do
+                       for mclassdef in mclass.mclassdefs do
+                               if not accept_mentity(mclassdef) then continue
+                               mclassdefs.add mclassdef
+                       end
+               end
+               return mclassdefs
+       end
+
+       # MProperties visible through `self`.
+       var mproperties: Set[MProperty] is lazy do
+               var mproperties = new HashSet[MProperty]
+               for mproperty in model.mproperties do
+                       if not accept_mentity(mproperty) then continue
+                       mproperties.add mproperty
+               end
+               return mproperties
+       end
+
+       # MPropdefs visible through `self`.
+       var mpropdefs: Set[MPropDef] is lazy do
+               var mpropdefs = new HashSet[MPropDef]
+               for mproperty in mproperties do
+                       for mpropdef in mproperty.mpropdefs do
+                               if not accept_mentity(mpropdef) then continue
+                               mpropdefs.add mpropdef
+                       end
+               end
+               return mpropdefs
+       end
+
+       # Lists all MEntities visible through `self`.
+       var mentities: Set[MEntity] is lazy do
+               var res = new HashSet[MEntity]
+               res.add_all mpackages
+               res.add_all mgroups
+               res.add_all mmodules
+               res.add_all mclasses
+               res.add_all mclassdefs
+               res.add_all mproperties
+               res.add_all mpropdefs
+               return res
+       end
+
+       private fun init_visitor(v: ModelVisitor) do
+               v.min_visibility = self.min_visibility
+               v.include_fictive = self.include_fictive
+               v.include_empty_doc = self.include_empty_doc
+               v.include_attribute = self.include_attribute
+               v.include_test_suite = self.include_test_suite
+       end
+
+       # Searches MEntities that match `name`.
+       fun mentities_by_name(name: String): Array[MEntity] do
+               var res = new Array[MEntity]
+               for mentity in mentities do if mentity.name == name then res.add mentity
+               return res
+       end
+
+       # Looks up a MEntity by its full `namespace`.
+       #
+       # Usefull when `mentities_by_name` returns conflicts.
+       #
+       # Namespaces must be of the form `package::core::module::Class::prop`.
+       fun mentities_by_namespace(namespace: String): Array[MEntity] do
+               var v = new LookupNamespaceVisitor(namespace)
+               init_visitor(v)
+               for mpackage in mpackages do
+                       v.enter_visit(mpackage)
+               end
+               return v.results
+       end
+
+       # Build an concerns tree with from `self`
+       fun to_tree: MEntityTree do
+               var v = new ModelTreeVisitor
+               init_visitor(v)
+               for mpackage in mpackages do
+                       v.enter_visit(mpackage)
+               end
+               return v.tree
+       end
+end
+
+class LookupNamespaceVisitor
+       super ModelVisitor
+
+       var namespace: String
+
+       private var parts: Array[String] is lazy do return namespace.split_with("::")
+
+       var results = new Array[MEntity]
+
+       redef fun visit(mentity) do mentity.accept_namespace_visitor(self)
+end
+
+class ModelTreeVisitor
+       super ModelVisitor
+
+       var tree = new MEntityTree
+
+       redef fun visit(mentity) do mentity.accept_tree_visitor(self)
+end
+
+redef class MEntity
+
+       # Get a public view of the model
+       fun public_view: ModelView do
+               var view = new ModelView(self.model)
+               view.min_visibility = public_visibility
+               return view
+       end
+
+       # Get a public view of the model
+       fun protected_view: ModelView do
+               var view = new ModelView(self.model)
+               view.min_visibility = protected_visibility
+               return view
+       end
+
+       # Get a public view of the model
+       fun private_view: ModelView do
+               var view = new ModelView(self.model)
+               view.min_visibility = private_visibility
+               return view
+       end
+
+       private fun accept_namespace_visitor(v: LookupNamespaceVisitor) do
+               if v.parts.is_empty then return
+               if name != v.parts.first then return
+               v.parts.shift
+               if v.parts.is_empty then
+                       v.results.add self
+                       return
+               end
+               visit_all(v)
+       end
+
+       private fun accept_tree_visitor(v: ModelTreeVisitor) do end
+end
+
+redef class MPackage
+       redef fun accept_tree_visitor(v) do
+               v.tree.add(null, self)
+               visit_all(v)
+       end
+end
+
+redef class MGroup
+       redef fun accept_tree_visitor(v) do
+               var parent = self.parent
+               if parent != null then
+                       v.tree.add(parent, self)
+               else
+                       v.tree.add(mpackage, self)
+               end
+               visit_all(v)
+       end
+end
+
+redef class MModule
+       redef fun accept_tree_visitor(v) do
+               v.tree.add(mgroup, self)
+               visit_all(v)
+       end
+end
+
+redef class MClass
+       # We don't want to collect classes from full namespace.
+       redef fun accept_namespace_visitor(v) do end
+end
+
+redef class MClassDef
+       redef fun accept_tree_visitor(v) do
+               v.tree.add(mmodule, self)
+               visit_all(v)
+       end
+end
+
+redef class MProperty
+       # We don't want to collect properties from full namespace.
+       redef fun accept_namespace_visitor(v) do end
+end
+
+redef class MPropDef
+       redef fun accept_tree_visitor(v) do
+               v.tree.add(mclassdef, self)
+               visit_all(v)
+       end
+end