--- /dev/null
+#!/bin/bash
+
+# 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.
+
+# This shell script creates (or overrides) a package.ini template file in the current directory.
+# The result must be examined and adapted.
+#
+# Default values are guessed from git and the file system.
+
+while true; do
+ case "$1" in
+ "")
+ break
+ ;;
+ -h|--help)
+ echo "nit-makepackage: creates a package.ini in the current directory"
+ echo "There is no option (yet)"
+ exit
+ ;;
+ *)
+ echo >&2 "nit-makepackage does not accept options yet"
+ exit 1
+ ;;
+ esac
+done
+
+
+name=`basename $PWD`
+maintainer=`git shortlog -esn . | head -n 1 | sed 's/\s*[0-9]*\s*//'`
+dir=`git rev-parse --show-prefix`
+git=`git remote get-url origin`
+
+# Setup default keys.
+# The following values works for Github and Gitlab
+root=${git%.git}
+browse=$root
+homepage=$root
+if [ -n "$dir" ]; then
+ browse=$root/tree/master/$dir
+fi
+issues=$root/issues
+
+# Special cases to override
+case "$git" in
+ */nit.git)
+ # For projects on the main Nit tree
+ license=Apache-2.0
+ git=https://github.com/nitlang/nit.git
+ homepage=http://nitlanguage.org
+ root=https://github.com/nitlang/nit
+ browse=$root/tree/master/$dir
+ issues=$root/issues
+ ;;
+esac
+
+# Generate the `package.ini` file
+sed '/^$/d' > package.ini <<SUPERCALIFRAGILISTICEXPIALIDOCIOUS
+[package]
+name=$name
+tags=
+maintainer=$maintainer
+license=$license
+[upstream]
+browse=$browse
+git=$git
+`test -n "$dir" && echo "git.directory=$dir"`
+homepage=$homepage
+issues=$issues
+SUPERCALIFRAGILISTICEXPIALIDOCIOUS
end
# Display respawn instructions
- app.ui_sprites.add new Sprite(app.texts_sheet.respawn, app.ui_camera.center)
+ app.ui_sprites.add new Sprite(app.texts_sheet.respawn, app.ui_camera.center.offset(0.0, 0.0, 0.0))
end
end
git.directory=contrib/nitrpg/
homepage=http://nitlanguage.org
issues=https://github.com/nitlang/nit/issues
-tryit=http://nitlanguage.org/rpg/games/nitlang/nit
update_oot() {
if test -d "$dir"; then
echo "$name: git pull"
+ ../misc/jenkins/unitrun.sh "cmd-$name-remote" git --work-tree="$PWD/$dir" --git-dir="$PWD/$dir/.git" remote set-url origin "$repo"
../misc/jenkins/unitrun.sh "cmd-$name-pull" git --work-tree="$PWD/$dir" --git-dir="$PWD/$dir/.git" pull -f
else
echo "$name: git clone"
# Format: repo name
https://github.com/R4PaSs/brewnit.git brewnit
https://gitlab.com/xymus/darpg.git darpg
+https://gitlab.com/jeremlvt/dawn_arrival.git dawn_arrival
https://github.com/Morriar/Missions.git missions
+https://gitlab.com/Heavyshield/NitGains.git nitgains
https://github.com/ppepos/pep8-dbg.git pep8dbg
https://gitlab.com/xymus/sputnit.git sputnit
git.directory=examples/calculator/
homepage=http://nitlanguage.org
issues=https://github.com/nitlang/nit/issues
-apk=http://nitlanguage.org/fdroid/apk/calculator21.apk
+apk=http://nitlanguage.org/fdroid/apk/calculator.apk
--- /dev/null
+[package]
+name=actors
+tags=parallelism,lib
+maintainer=Romain Chanoir <romain.chanoir@viacesi.fr>
+license=Apache-2.0
+[upstream]
+browse=https://github.com/nitlang/nit/tree/master/lib/actors/
+git=https://github.com/nitlang/nit.git
+git.directory=lib/actors/
+homepage=http://nitlanguage.org
+issues=https://github.com/nitlang/nit/issues
#
# Prints on communication errors and when the server returns an HTTP status code not in the 200s.
#
-# ~~~
+# ~~~nitish
# var request = new SimpleAsyncHttpRequest("http://example.com")
# request.start
# ~~~
# return true if a file with this names exists
fun file_exists: Bool do return to_cstring.file_exists
-end
-redef class String
# The status of a file. see POSIX stat(2).
fun file_stat: nullable FileStat
do
if extension == null then
extension = file_extension
if extension == null then
- return self
+ return self.to_s
else extension = ".{extension}"
end
if has_suffix(extension) then
- return substring(0, length - extension.length)
+ return substring(0, length - extension.length).to_s
end
- return self
+ return self.to_s
end
# Extract the basename of a path and strip the `extension`
if extension != null then
return n.strip_extension(extension)
- else return n
+ else return n.to_s
end
# Extract the dirname of a path
while l > 0 and s.chars[l] == '/' do l -= 1 # remove all trailing `/`
var pos = s.chars.last_index_of_from('/', l)
if pos > 0 then
- return s.substring(0, pos)
+ return s.substring(0, pos).to_s
else if pos == 0 then
return "/"
else
# Note: You may want to use `simplify_path` on the result.
#
# Note: This method works only with POSIX paths.
- fun join_path(path: String): String
+ fun join_path(path: Text): String
do
- if path.is_empty then return self
- if self.is_empty then return path
- if path.chars[0] == '/' then return path
+ if path.is_empty then return self.to_s
+ if self.is_empty then return path.to_s
+ if path.chars[0] == '/' then return path.to_s
if self.last == '/' then return "{self}{path}"
return "{self}/{path}"
end
# assert "".to_program_name == "./" # At least, your shell will detect the error.
fun to_program_name: String do
if self.has_prefix("/") then
- return self
+ return self.to_s
else
return "./{self}"
end
# var b = "/bar"
# var c = "baz/foobar"
# assert a/b/c == "/bar/baz/foobar"
- fun /(path: String): String do return join_path(path)
+ fun /(path: Text): String do return join_path(path)
# Returns the relative path needed to go from `self` to `dest`.
#
do
var last_slash = chars.last_index_of('.')
if last_slash > 0 then
- return substring( last_slash+1, length )
+ return substring( last_slash+1, length ).to_s
else
return null
end
if args.is_empty then
print graph.to_dot
- graph.show
+ # graph.show
else
graph.to_dot.write_to_file args.first
end
# ~~~
# redef class App
# var font = new BMFontAsset("arial.fnt")
-# var ui_text = new TextSprites(font, ui_camera.top_left)
+# var pos: Point3d[Float] = ui_camera.top_left.offset(128.0, -128.0, 0.0)
+# var ui_text = new TextSprites(font, pos)
#
# redef fun on_create
# do
var display: GamnitDisplay
# Position of this camera in world space
- var position = new Point3d[Float](0.0, 0.0, 0.0) is writable
+ var position = new Point3d[Float](0.0, 0.0, 0.0)
# The Model-View-Projection matrix created by this camera
#
# Clipping wall the farthest of the camera, defaults to -100.0
var far: Float = -100.0 is writable
- # Width in world units, defaults to the width in pixels of the screen
- var width: Float = display.width.to_f is lazy
+ # Width in world units, calculated from `height` and the screen aspect ratio
+ fun width: Float do return height * display.aspect_ratio
- # Height in world units, defaults to the height in pixels of the screen
- var height: Float = display.height.to_f is lazy
+ # Height in world units, defaults to 1080.0
+ #
+ # Set this value using `reset_height`.
+ var height = 1080.0
# Reset the camera position so that `height` world units are visible on the Y axis
#
- # By default, `height` is set to `display.height`.
- #
# This can be used to set standardized UI units independently from the screen resolution.
fun reset_height(height: nullable Float)
do
if height == null then height = display.height.to_f
-
self.height = height
- self.width = height * display.aspect_ratio
end
# Convert the position `x, y` on screen, to UI coordinates
end
# Center of the screen, from the point of view of the camera, at z = 0
- fun center: Point3d[Float] do return new Point3d[Float](position.x + width / 2.0, position.y - height / 2.0, 0.0)
+ var center: IPoint3d[Float] = new CameraAnchor(self, 0.5, -0.5)
# Center of the top of the screen, at z = 0
- fun top: Point3d[Float] do return new Point3d[Float](position.x + width / 2.0, position.y, 0.0)
+ var top: IPoint3d[Float] = new CameraAnchor(self, 0.5, 0.0)
# Center of the bottom of the screen, at z = 0
- fun bottom: Point3d[Float] do return new Point3d[Float](position.x + width / 2.0, position.y - height, 0.0)
+ var bottom: IPoint3d[Float] = new CameraAnchor(self, 0.5, -1.0)
# Center of the left border of the screen, at z = 0
- fun left: Point3d[Float] do return new Point3d[Float](position.x, position.y - height / 2.0, 0.0)
+ var left: IPoint3d[Float] = new CameraAnchor(self, 0.0, -1.0)
# Center of the right border of the screen, at z = 0
- fun right: Point3d[Float] do return new Point3d[Float](position.x + width, position.y - height / 2.0, 0.0)
+ var right: IPoint3d[Float] = new CameraAnchor(self, 1.0, -1.0)
# Top left corner of the screen, at z = 0
- fun top_left: Point3d[Float] do return new Point3d[Float](position.x, position.y, 0.0)
+ var top_left: IPoint3d[Float] = new CameraAnchor(self, 0.0, 0.0)
# Top right corner of the screen, at z = 0
- fun top_right: Point3d[Float] do return new Point3d[Float](position.x + width, position.y, 0.0)
+ var top_right: IPoint3d[Float] = new CameraAnchor(self, 1.0, 0.0)
# Bottom left corner of the screen, at z = 0
- fun bottom_left: Point3d[Float] do return new Point3d[Float](position.x, position.y - height, 0.0)
+ var bottom_left: IPoint3d[Float] = new CameraAnchor(self, 0.0, -1.0)
# Bottom right corner of the screen, at z = 0
- fun bottom_right: Point3d[Float] do return new Point3d[Float](position.x + width, position.y - height, 0.0)
-
- # TODO cache the anchors
+ var bottom_right: IPoint3d[Float] = new CameraAnchor(self, 1.0, -1.0)
redef fun mvp_matrix
do
return view * projection
end
end
+
+# Immutable relative anchors for reference points on `camera`
+private class CameraAnchor
+ super IPoint3d[Float]
+
+ # Reference camera
+ var camera: UICamera
+
+ # Reference position, the top left of the screen
+ var ref: Point3d[Float] = camera.position is lazy
+
+ # X position as proportion of the screen width
+ var relative_x: Float
+
+ # Y position as proportion of the screen height
+ var relative_y: Float
+
+ redef fun x do return ref.x + relative_x*camera.width
+ redef fun y do return ref.y + relative_y*camera.height
+ redef fun z do return ref.z
+
+ redef fun offset(x, y, z) do return new OffsetPoint3d(self, x.to_f, y.to_f, z.to_f)
+end
+
+# Position relative to another point or usually a `CameraAnchor`
+private class OffsetPoint3d
+ super Point3d[Float]
+
+ autoinit ref, offset_x, offset_y, offset_z
+
+ # Reference point to which the offsets are applied
+ var ref: IPoint3d[Float]
+
+ # Difference on the X axis
+ var offset_x: Float
+
+ # Difference on the X axis
+ var offset_y: Float
+
+ # Difference on the X axis
+ var offset_z: Float
+
+ redef fun x do return ref.x + offset_x
+ redef fun y do return ref.y + offset_y
+ redef fun z do return ref.z + offset_z
+
+ redef fun x=(value) do if value != null then offset_x += value - x
+ redef fun y=(value) do if value != null then offset_y += value - y
+ redef fun z=(value) do if value != null then offset_z += value - z
+
+ redef fun offset(x, y, z) do return new OffsetPoint3d(self, x.to_f, y.to_f, z.to_f)
+end
mvp_matrix_cache = null
end
- redef fun width=(value)
- do
- super
- mvp_matrix_cache = null
- end
-
redef fun height=(value)
do
super
# Draw all elements of `actors` and then call `frame_core_flat`
protected fun frame_core_depth(display: GamnitDisplay)
do
+ glViewport(0, 0, display.width, display.height)
frame_core_dynamic_resolution_before display
# Update cameras on both our programs
fun height: Int is abstract
# Aspect ratio of the screen, `width / height`
- var aspect_ratio: Float is lazy do return width.to_f / height.to_f
+ fun aspect_ratio: Float do return width.to_f / height.to_f
# Is the cursor locked et the center of the screen?
var lock_cursor = false is writable
print_error "Failed to initialize SDL2 IMG: {sdl.error}"
end
- var sdl_window = new SDLWindow(window_title.to_cstring, window_width, window_height, (new SDLWindowFlags).opengl)
+ var sdl_window = new SDLWindow(window_title.to_cstring, window_width, window_height, sdl_window_flags)
assert not sdl_window.address_is_null else
print_error "Failed to create SDL2 window: {sdl.error}"
end
return sdl_window
end
- # Initialization flags passed to SDL2 mixer
+ # SDL2 window initialization flags
+ #
+ # The default value supports OpenGL and window resizing.
+ var sdl_window_flags: SDLWindowFlags = (new SDLWindowFlags).opengl.resizable is lazy, writable
+
+ # SDL2 mixer initialization flags
#
# Defaults to all available formats.
var mix_init_flags: MixInitFlags = mix.flac | mix.mod | mix.mp3 | mix.ogg is lazy, writable
assert error == null else print_error error
end
+ redef fun on_resize(display)
+ do
+ dynamic_context.resize(display, max_dynamic_resolution_ratio)
+ super
+ end
+
# Prepare to draw to the dynamic screen if `dynamic_resolution_ratio != 1.0`
protected fun frame_core_dynamic_resolution_before(display: GamnitDisplay)
do
# Draw directly to the screen framebuffer
glBindFramebuffer(gl_FRAMEBUFFER, dynamic_context.screen_framebuffer)
glViewport(0, 0, display.width, display.height)
+ glClear gl_COLOR_BUFFER_BIT | gl_DEPTH_BUFFER_BIT
var gl_error = glGetError
assert gl_error == gl_NO_ERROR else print_error gl_error
# Draw to our dynamic framebuffer
glBindFramebuffer(gl_FRAMEBUFFER, dynamic_context.dynamic_framebuffer)
- glClear gl_COLOR_BUFFER_BIT | gl_DEPTH_BUFFER_BIT
var ratio = dynamic_resolution_ratio
ratio = ratio.clamp(min_dynamic_resolution_ratio, max_dynamic_resolution_ratio)
glViewport(0, 0, (display.width.to_f*ratio).to_i,
(display.height.to_f*ratio).to_i)
+ glClear gl_COLOR_BUFFER_BIT | gl_DEPTH_BUFFER_BIT
+
var gl_error = glGetError
assert gl_error == gl_NO_ERROR else print_error gl_error
end
do
# TODO enable antialiasing.
- var width = (display.width.to_f * max_dynamic_resolution_ratio).to_i
- var height = (display.height.to_f * max_dynamic_resolution_ratio).to_i
-
# Set aside the real screen framebuffer name
var screen_framebuffer = glGetIntegerv(gl_FRAMEBUFFER_BINDING, 0)
self.screen_framebuffer = screen_framebuffer
glBindFramebuffer(gl_FRAMEBUFFER, framebuffer)
assert glIsFramebuffer(framebuffer)
self.dynamic_framebuffer = framebuffer
+ var gl_error = glGetError
+ assert gl_error == gl_NO_ERROR else print_error gl_error
- # Depth
+ # Depth & texture/color
var depthbuffer = glGenRenderbuffers(1).first
- glBindRenderbuffer(gl_RENDERBUFFER, depthbuffer)
- assert glIsRenderbuffer(depthbuffer)
- glRenderbufferStorage(gl_RENDERBUFFER, gl_DEPTH_COMPNENT16, width, height)
- glFramebufferRenderbuffer(gl_FRAMEBUFFER, gl_DEPTH_ATTACHMENT, gl_RENDERBUFFER, depthbuffer)
self.depth_renderbuffer = depthbuffer
-
- # Texture
var texture = glGenTextures(1).first
- glBindTexture(gl_TEXTURE_2D, texture)
- glTexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MIN_FILTER, gl_LINEAR)
- glTexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MAG_FILTER, gl_LINEAR)
- glTexParameteri(gl_TEXTURE_2D, gl_TEXTURE_WRAP_S, gl_CLAMP_TO_EDGE)
- glTexParameteri(gl_TEXTURE_2D, gl_TEXTURE_WRAP_T, gl_CLAMP_TO_EDGE)
- glTexImage2D(gl_TEXTURE_2D, 0, gl_RGB, width, height,
- 0, gl_RGB, gl_UNSIGNED_BYTE, new Pointer.nul)
- glFramebufferTexture2D(gl_FRAMEBUFFER, gl_COLOR_ATTACHMENT0, gl_TEXTURE_2D, texture, 0)
self.texture = texture
-
- var gl_error = glGetError
+ gl_error = glGetError
assert gl_error == gl_NO_ERROR else print_error gl_error
- assert glCheckFramebufferStatus(gl_FRAMEBUFFER) == gl_FRAMEBUFFER_COMPLETE
- # Take down
- glBindRenderbuffer(gl_RENDERBUFFER, 0)
- glBindFramebuffer(gl_FRAMEBUFFER, 0)
+ resize(display, max_dynamic_resolution_ratio)
+ assert glCheckFramebufferStatus(gl_FRAMEBUFFER) == gl_FRAMEBUFFER_COMPLETE
# Array buffer
buffer_array = glGenBuffers(1).first
assert gl_error == gl_NO_ERROR else print_error gl_error
end
+ # Init size or resize `depth_renderbuffer` and `texture`
+ fun resize(display: GamnitDisplay, max_dynamic_resolution_ratio: Float)
+ do
+ var width = (display.width.to_f * max_dynamic_resolution_ratio).to_i
+ var height = (display.height.to_f * max_dynamic_resolution_ratio).to_i
+
+ glBindFramebuffer(gl_FRAMEBUFFER, dynamic_framebuffer)
+
+ var depthbuffer = self.depth_renderbuffer
+ var texture = self.texture
+
+ # Depth
+ glBindRenderbuffer(gl_RENDERBUFFER, depthbuffer)
+ assert glIsRenderbuffer(depthbuffer)
+ glRenderbufferStorage(gl_RENDERBUFFER, gl_DEPTH_COMPNENT16, width, height)
+ glFramebufferRenderbuffer(gl_FRAMEBUFFER, gl_DEPTH_ATTACHMENT, gl_RENDERBUFFER, depthbuffer)
+ var gl_error = glGetError
+ assert gl_error == gl_NO_ERROR else print_error gl_error
+
+ # Texture
+ glBindTexture(gl_TEXTURE_2D, texture)
+ glTexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MIN_FILTER, gl_LINEAR)
+ glTexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MAG_FILTER, gl_LINEAR)
+ glTexParameteri(gl_TEXTURE_2D, gl_TEXTURE_WRAP_S, gl_CLAMP_TO_EDGE)
+ glTexParameteri(gl_TEXTURE_2D, gl_TEXTURE_WRAP_T, gl_CLAMP_TO_EDGE)
+ glTexImage2D(gl_TEXTURE_2D, 0, gl_RGB, width, height,
+ 0, gl_RGB, gl_UNSIGNED_BYTE, new Pointer.nul)
+ glFramebufferTexture2D(gl_FRAMEBUFFER, gl_COLOR_ATTACHMENT0, gl_TEXTURE_2D, texture, 0)
+
+ gl_error = glGetError
+ assert gl_error == gl_NO_ERROR else print_error gl_error
+
+ # Take down
+ glBindRenderbuffer(gl_RENDERBUFFER, 0)
+ glBindFramebuffer(gl_FRAMEBUFFER, 0)
+
+ gl_error = glGetError
+ assert gl_error == gl_NO_ERROR else print_error gl_error
+ end
+
var destroyed = false
fun destroy
do
import performance_analysis
import gamnit
-import gamnit::cameras_cache
+intrude import gamnit::cameras
+intrude import gamnit::cameras_cache
import gamnit::dynamic_resolution
import gamnit::limit_fps
import gamnit::camera_control
do
texture.load
- ui_camera.reset_height 1080.0
-
- var splash = new Sprite(texture, ui_camera.center)
+ var splash = new Sprite(texture, ui_camera.center.offset(0.0, 0.0, 0.0))
ui_sprites.add splash
var display = display
if display != null then display.close
end
- redef fun frame_core(display)
+ redef fun on_resize(display)
do
- # Prepare to draw, clear buffers
- glClear(gl_COLOR_BUFFER_BIT | gl_DEPTH_BUFFER_BIT)
+ super
+
+ world_camera.mvp_matrix_cache = null
+ ui_camera.mvp_matrix_cache = null
+ # Update all sprites in the UI
+ for sprite in ui_sprites do sprite.needs_update
+ end
+
+ redef fun frame_core(display)
+ do
# Check errors
var gl_error = glGetError
assert gl_error == gl_NO_ERROR else print_error gl_error
end
redef class Point3d[N]
- # Get a new `Point3d[Float]` with an offset of each axis of `x, y, z`
- fun offset(x, y, z: Numeric): Point3d[Float]
- do
- return new Point3d[Float](self.x.to_f+x.to_f, self.y.to_f+y.to_f, self.z.to_f+z.to_f)
- end
-
# ---
# Associate each point to its sprites
end
end
+redef class OffsetPoint3d
+ redef fun x=(v)
+ do
+ if isset _x and v != x then needs_update
+ super
+ end
+
+ redef fun y=(v)
+ do
+ if isset _y and v != y then needs_update
+ super
+ end
+
+ redef fun z=(v)
+ do
+ if isset _z and v != z then needs_update
+ super
+ end
+end
+
# Set of sprites sorting them into different `SpriteContext`
private class SpriteSet
super HashSet[Sprite]
# The instances passed as `event` may be freed (or overwritten),
# right after this method returns. They should not be preserved.
fun accept_event(event: InputEvent): Bool do return false
+
+ # The window has been resized by the user or system
+ #
+ # The framework handles resizing the viewport automatically.
+ fun on_resize(display: GamnitDisplay) do end
end
import sdl2::events
intrude import gamnit
+intrude import display_linux
redef class App
private var sdl_event_buffer = new SDLEventBuffer.malloc
# Convert to an SDL event with data
var sdl_event = sdl_event_buffer.to_event
+ if sdl_event isa SDLWindowEvent and sdl_event.is_resized then
+ display.width = sdl_event.data1
+ display.height = sdl_event.data2
+ on_resize display
+ end
+
# Convert to `mnit::inputs` conforming objects
var gamnit_event = sdl_event.to_gamnit_event(sdl_event_buffer)
accept_event gamnit_event
var s = dist2_xy(other).add(dz.mul(dz))
return x.value_of(s)
end
+
+ # Get a new `Point3d[Float]` at an offset of `x, y, z` from `self`
+ #
+ # ~~~
+ # var origin = new Point3d[Float](1.0, 1.0, 1.0)
+ # assert origin.offset(1.0, 2.0, 3.0).to_s == "(2.0, 3.0, 4.0)"
+ # ~~~
+ fun offset(x, y, z: Numeric): Point3d[Float]
+ do return new Point3d[Float](self.x.to_f+x.to_f,
+ self.y.to_f+y.to_f,
+ self.z.to_f+z.to_f)
end
# 3D point with `x`, `y` and `z`
--- /dev/null
+[package]
+name=gmp
+tags=maths,lib
+maintainer=PatrickBlanchette <PatrickBlanchette@users.noreply.github.com>
+license=Apache-2.0
+[upstream]
+browse=https://github.com/nitlang/nit/tree/master/lib/gmp/
+git=https://github.com/nitlang/nit.git
+git.directory=lib/gmp/
+homepage=http://nitlanguage.org
+issues=https://github.com/nitlang/nit/issues
self.params = params
end
+ # Pass the argument `value` as the parameter `key`.
+ #
+ # SEE: `set`
+ fun []=(key: String, value: nullable Serializable) do
+ params[key] = value
+ end
+
# Add a `CREATE` statement to the query
fun ncreate(query: String): CypherQuery do
self.query = "{self.query}CREATE {query} "
return self
end
+ # Pass the argument `value` as the parameter `key`.
+ #
+ # Return `self`.
+ #
+ # ```
+ # var query = (new CypherQuery).nmatch("(n)").nwhere(
+ # "n.key = key").set("key", "foo")
+ #
+ # assert query.params["key"] == "foo"
+ # ```
+ #
+ # SEE: `[]=`
+ fun set(key: String, value: nullable Serializable): SELF do
+ self[key] = value
+ return self
+ end
+
# Translate the query to the body of a corresponding Neo4j REST request.
fun to_rest: JsonObject do
var obj = new JsonObject
module pop_json
import json
+import meta
import pop_handlers
import pop_validation
fun deserialize_body(req: HttpRequest, res: HttpResponse): nullable BODY do
var body = req.body
var deserializer = new JsonDeserializer(body)
- var form = deserializer.deserialize(body)
+ var form = deserializer.deserialize(body_type)
if not form isa BODY or deserializer.errors.not_empty then
res.json_error("Bad input", 400)
return null
#
# Define it in each sub handlers depending on the kind of objects sent in request bodies.
type BODY: Serializable
+
+ private var body_type: String is lazy do return (new GetName[BODY]).to_s
end
redef class HttpResponse
end
end
+# Check if a field is a Bool
+#
+# ~~~
+# var validator = new ObjectValidator
+# validator.add new BoolField("field", required=false)
+# assert validator.validate("""{}""")
+# assert validator.validate("""{ "field": true }""")
+# assert validator.validate("""{ "field": false }""")
+# assert not validator.validate("""{ "field": "foo" }""")
+#
+# validator = new ObjectValidator
+# validator.add new BoolField("field")
+# assert not validator.validate("""{}""")
+# assert validator.validate("""{ "field": true }""")
+# assert validator.validate("""{ "field": false }""")
+# assert not validator.validate("""{ "field": "foo" }""")
+# ~~~
+#
+# No type conversion is applied on the input value:
+# ~~~
+# assert not validator.validate("""{ "field": "true" }""")
+# assert not validator.validate("""{ "field": 1 }""")
+# assert not validator.validate("""{ "field": [true] }""")
+# ~~~
+class BoolField
+ super RequiredField
+
+ redef fun validate_field(v, obj) do
+ if not super then return false
+ var val = obj.get_or_null(field)
+ if val == null then
+ if required == null or required == true then
+ v.validation.add_error(field, "Expected Bool got `null`")
+ return false
+ else
+ return true
+ end
+ end
+ if not val isa Bool then
+ v.validation.add_error(field, "Expected Bool got `{val.class_name}`")
+ return false
+ end
+ return true
+ end
+end
+
# Check that a field is a JsonObject
#
# ~~~
if is_mouse_wheel then return to_mouse_wheel
if is_keydown then return to_keydown
if is_keyup then return to_keyup
+ if is_window then return to_window
return to_event_direct
end
# Require: `is_keyup`
fun to_keyup: SDLKeyboardUpEvent `{ return self; `}
+ # Is this a window event?
+ fun is_window: Bool `{ return self->type == SDL_WINDOWEVENT; `}
+
+ # Get a reference to data at `self` as a `SDLWindowEvent`
+ #
+ # Require: `is_window`
+ fun to_window: SDLWindowEvent `{ return self; `}
+
# TODO other SDL events:
#
# SDL_CommonEvent common
fun mod: Int `{ return self->mod; `}
# TODO related masks
end
+
+# Window event
+extern class SDLWindowEvent
+ super SDLEvent
+
+ # Window identifier
+ fun id: Int `{ return self->window.windowID; `}
+
+ # Is `self` a resized event?
+ fun is_resized: Bool `{ return self->window.event == SDL_WINDOWEVENT_RESIZED; `}
+
+ # Is `self` a size changed event?
+ fun is_size_changed: Bool `{ return self->window.event == SDL_WINDOWEVENT_SIZE_CHANGED; `}
+
+ # `data1` field, depends on the event kind
+ fun data1: Int `{ return self->window.data1; `}
+
+ # `data2` field, depends on the event kind
+ fun data2: Int `{ return self->window.data2; `}
+end
&& make \
&& . misc/nit_env.sh install \
# Clean and reduce size
- && strip c_src/nitc bin/nit* \
+ && { strip c_src/nitc bin/nit* || true; } \
&& ccache -C \
&& rm -rf .git
shift
# Detect a working time command
-if env time --quiet -f%U true 2>/dev/null; then
- TIME="env time --quiet -f%U -o ${name}.t.out"
-elif env time -f%U true 2>/dev/null; then
- TIME="env time -f%U -o ${name}.t.out"
-elif env gtime -f%U true 2>/dev/null; then
- TIME="env gtime -f%U -o ${name}.t.out"
+if command time --quiet -f%e true 2>/dev/null; then
+ TIME="command time --quiet -f%e -o ${name}.t.out"
+elif command time -f%e true 2>/dev/null; then
+ TIME="command time -f%e -o ${name}.t.out"
+elif command gtime -f%e true 2>/dev/null; then
+ TIME="command gtime -f%e -o ${name}.t.out"
else
TIME=
fi
--- /dev/null
+# NAME
+
+nit-makepackage - helper script to setup package metadata
+
+# SYNOPSIS
+
+nit-makepackage
+
+# DESCRIPTION
+
+`nit-makepackage` creates (or overrides) a package.ini template file in the current directory.
+The result must be examined and adapted.
+
+Default values are guessed from git and the file system.
+
+# SEE ALSO
+
+The Nit language documentation and the source code of its tools and libraries may be downloaded from <http://nitlanguage.org>
-<div class='card card-xl' ng-class='{active: isActive()}'>
+<div class='card card-xl' ng-class='{active: isActive()}' id='{{definition.full_name}}'>
<div class='card-body'>
<h5>
<span ng-if='definition.is_intro'>
<span>
- <a ng-href='{{mentity.web_url | encodeURI}}'>{{mentity.name}}</a>
+ <a ng-href='{{mentity.web_url}}'>{{mentity.name}}</a>
</span>
-<div id="{{chartId}}"></div>
+<div id="{{chartId}}" ng-if='chartMetrics'></div>
-<div class='card'>
+<div class='card' ng-if='listMetrics'>
<div class='card-body'>
<h4 class='card-heading'>{{listTitle}}</h4>
<table class='table'>
--- /dev/null
+<form style='margin-bottom: 0'>
+ <div class='form-group has-icon'>
+ <input placeholder='Search...' type='text' class='form-control search-input'
+ ng-model-options='{ debounce: 300 }' ng-model='vm.query'
+ ng-keydown='update($event)' ng-change='vm.search()'>
+ <span class='glyphicon glyphicon-search form-control-icon text-muted'></span>
+ </div>
+</form>
type='text/css' rel='stylesheet'>
- <link href='/stylesheets/nitweb_bootstrap.css' rel='stylesheet'>
- <link href='/stylesheets/nitweb.css' rel='stylesheet'>
+ <link rel='stylesheet' href='/stylesheets/nitweb_bootstrap.css'>
+ <link rel='stylesheet' href='/stylesheets/nitweb.css'>
+ <link rel='stylesheet' href='/stylesheets/nitlight.css'>
+ <link rel='stylesheet' href='/stylesheets/search.css'>
+ <link rel='stylesheet' href='/stylesheets/cards.css'>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.4.4/d3.min.js"></script>
<script src="/vendors/d3pie.min.js"></script>
</div>
</div>
</nav>
- <div ng-view></div>
+ <ui-view></ui-view>
<script src='https://code.jquery.com/jquery-1.12.4.min.js'
integrity='sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ='
crossorigin='anonymous'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.5/angular.min.js'>
</script>
- <script src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.5/angular-route.js'>
- </script>
+ <script src='http://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.3.1/angular-ui-router.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.5/angular-sanitize.js'>
</script>
<script src='//cdnjs.cloudflare.com/ajax/libs/angular-loading-bar/0.9.0/loading-bar.min.js'>
</script>
<script src='/javascripts/nitweb.js'></script>
- <script src='/javascripts/model.js'></script>
<script src='/javascripts/entities.js'></script>
<script src='/javascripts/ui.js'></script>
<script src='/javascripts/index.js'></script>
(function() {
angular
- .module('docdown', ['model', 'ngSanitize'])
+ .module('docdown', ['ngSanitize'])
- .controller('DocdownCtrl', ['$routeParams', '$sce', '$scope', '$location', 'DocDown', function($routeParams, $sce, $scope, $location, DocDown) {
+ .config(function($stateProvider, $locationProvider) {
+ $stateProvider
+ .state('docdown', {
+ url: '/docdown',
+ templateUrl: 'views/docdown.html',
+ controller: 'DocdownCtrl',
+ controllerAs: 'docdownCtrl'
+ })
+ })
+
+ .factory('DocDown', [ '$http', function($http) {
+ return {
+ postMarkdown: function(md, cb, cbErr) {
+ $http.post('/api/docdown', md)
+ .success(cb)
+ .error(cbErr);
+ }
+ }
+ }])
+
+ .controller('DocdownCtrl', ['$sce', '$scope', '$location', 'DocDown', function($sce, $scope, $location, DocDown) {
this.updateSnippet = function() {
this.updateLink();
(function() {
angular
- .module('entities', ['ngSanitize', 'ui', 'model'])
+ .module('entities', ['ngSanitize', 'ui'])
- .controller('EntityCtrl', ['Model', 'Metrics', 'Feedback', '$routeParams', '$scope', '$sce', function(Model, Metrics, Feedback, $routeParams, $scope, $sce) {
- $scope.entityId = $routeParams.id;
+ /* Router */
- this.loadEntityLinearization = function() {
- Model.loadEntityLinearization($routeParams.id,
- function(data) {
- $scope.linearization = data;
- }, function(err) {
- $scope.error = err;
- });
- };
+ .config(function($stateProvider, $locationProvider) {
+ $stateProvider
+ .state('doc', {
+ url: '/doc/:id',
+ templateUrl: 'views/doc/index.html',
+ resolve: {
+ mentity: function(Model, $q, $stateParams, $state) {
+ var d = $q.defer();
+ Model.loadEntity($stateParams.id, d.resolve,
+ function() {
+ $state.go('404', null, { location: false })
+ });
+ return d.promise;
+ }
+ },
+ controller: function(mentity) {
+ this.mentity = mentity;
+ },
+ controllerAs: 'vm',
+ abstract: true
+ })
+ .state('doc.entity', {
+ url: '',
+ templateUrl: 'views/doc/entity.html',
+ controller: function(mentity) {
+ this.mentity = mentity;
+ },
+ controllerAs: 'vm',
+ abstract: true
+ })
+ .state('doc.entity.doc', {
+ url: '',
+ templateUrl: 'views/doc/doc.html',
+ controller: function(mentity) {
+ this.mentity = mentity;
+ },
+ controllerAs: 'vm',
+ })
+ .state('doc.entity.graph', {
+ url: '/graph',
+ templateUrl: 'views/doc/graph.html',
+ resolve: {
+ graph: function(Model, $q, $stateParams, $state) {
+ var d = $q.defer();
+ Model.loadEntityGraph($stateParams.id, d.resolve,
+ function() {
+ $state.go('404', null, { location: false })
+ });
+ return d.promise;
+ }
+ },
+ controller: function(graph, $sce) {
+ this.graph = $sce.trustAsHtml(graph);
+ },
+ controllerAs: 'vm',
+ })
+ .state('doc.entity.metrics', {
+ url: '/metrics',
+ templateUrl: 'views/doc/metrics.html',
+ resolve: {
+ metrics: function(Metrics, $q, $stateParams, $state) {
+ var d = $q.defer();
+ Metrics.loadStructuralMetrics($stateParams.id, d.resolve,
+ function() {
+ $state.go('404', null, { location: false })
+ });
+ return d.promise;
+ }
+ },
+ controller: function(mentity, metrics) {
+ this.mentity = mentity;
+ this.metrics = metrics;
+ },
+ controllerAs: 'vm',
+ })
+ .state('doc.entity.code', {
+ url: '/code',
+ templateUrl: 'views/doc/code.html',
+ resolve: {
+ code: function(Model, $q, $stateParams, $state) {
+ var d = $q.defer();
+ Model.loadEntityCode($stateParams.id, d.resolve,
+ function() {
+ $state.go('404', null, { location: false })
+ });
+ return d.promise;
+ }
+ },
+ controller: function(mentity, code) {
+ this.mentity = mentity;
+ this.code = code;
+ },
+ controllerAs: 'vm',
+ })
+ .state('doc.entity.defs', {
+ url: '/defs',
+ templateUrl: 'views/doc/defs.html',
+ resolve: {
+ defs: function(Model, $q, $stateParams, $state) {
+ var d = $q.defer();
+ Model.loadEntityDefs($stateParams.id, d.resolve,
+ function() {
+ $state.go('404', null, { location: false })
+ });
+ return d.promise;
+ }
+ },
+ controller: function(mentity, defs) {
+ this.mentity = mentity;
+ this.defs = defs;
+ },
+ controllerAs: 'vm',
+ })
+ .state('doc.entity.lin', {
+ url: '/lin',
+ templateUrl: 'views/doc/lin.html',
+ resolve: {
+ lin: function(Model, $q, $stateParams, $state) {
+ var d = $q.defer();
+ Model.loadEntityLinearization($stateParams.id, d.resolve,
+ function() {
+ $state.go('404', null, { location: false })
+ });
+ return d.promise;
+ }
+ },
+ controller: function(mentity, lin, $scope, $location, $anchorScroll) {
+ var vm = this;
+ vm.focus = $location.hash() ?
+ $location.hash() : mentity.intro.full_name;
+ vm.mentity = mentity;
+ vm.linearization = lin;
+ setTimeout(function() {
+ $anchorScroll();
+ }, 400);
+ $scope.$watch(function () {
+ return $location.hash();
+ }, function (value) {
+ vm.focus = $location.hash() ?
+ $location.hash() : mentity.intro.full_name;
+ $anchorScroll();
+ });
+ },
+ controllerAs: 'vm'
+ })
+ .state('doc.entity.all', {
+ url: '/all',
+ templateUrl: 'views/doc/all.html',
+ controller: function(mentity) {
+ this.mentity = mentity;
+ },
+ controllerAs: 'vm',
+ })
+ })
- this.loadEntityDefs = function() {
- Model.loadEntityDefs($routeParams.id,
- function(data) {
- $scope.defs = data;
- }, function(err) {
- $scope.error = err;
- });
- };
+ /* Model */
- this.loadEntityCode = function() {
- Model.loadEntityCode($routeParams.id,
- function(data) {
- $scope.code = data;
- }, function(err) {
- $scope.code = err;
- });
- };
+ .factory('Model', [ '$http', function($http) {
+ return {
- this.loadEntityGraph = function(e) {
- Model.loadEntityGraph($routeParams.id,
- function(data) {
- $scope.graph = $sce.trustAsHtml(data);
- }, function(err) {
- $scope.error = err;
- });
- };
+ loadEntity: function(id, cb, cbErr) {
+ $http.get('/api/entity/' + id)
+ .success(cb)
+ .error(cbErr);
+ },
- this.loadStructuralMetrics = function() {
- Metrics.loadStructuralMetrics($routeParams.id,
- function(data) {
- $scope.metrics = data;
- }, function(message, status) {
- $scope.error = {message: message, status: status};
- });
- };
+ loadEntityLinearization: function(id, cb, cbErr) {
+ $http.get('/api/linearization/' + id)
+ .success(cb)
+ .error(cbErr);
+ },
- Model.loadEntity($routeParams.id,
- function(data) {
- $scope.mentity = data;
- }, function(message, status) {
- $scope.error = {message: message, status: status};
- });
+ loadEntityDefs: function(id, cb, cbErr) {
+ $http.get('/api/defs/' + id)
+ .success(cb)
+ .error(cbErr);
+ },
+
+ loadEntityCode: function(id, cb, cbErr) {
+ $http.get('/api/code/' + id)
+ .success(cb)
+ .error(cbErr);
+ },
+
+ loadEntityGraph: function(id, cb, cbErr) {
+ $http.get('/api/graph/inheritance/' + id + '?cdepth=3')
+ .success(cb)
+ .error(cbErr);
+ },
+
+ search: function(q, n, cb, cbErr) {
+ $http.get('/api/search?q=' + q + '&n=' + n)
+ .success(cb)
+ .error(cbErr);
+ }
+ };
}])
+ /* Directives */
+
.directive('entityLink', function() {
return {
restrict: 'E',
$scope.codeId = 'code_' + $scope.definition.full_name.replace(/[^a-zA-Z0-9]/g, '_');
$scope.isActive = function() {
- return $scope.focus.full_name == $scope.definition.full_name;
+ return $scope.focus == $scope.definition.full_name;
}
$scope.loadCardCode = function() {
}
};
- if($scope.isActive()) $scope.loadCardCode();
+ $scope.$watch('focus', function() {
+ if($scope.isActive()) $scope.loadCardCode();
+ });
}
};
}])
(function() {
angular
- .module('grades', ['ngSanitize', 'model'])
+ .module('grades', ['ngSanitize'])
+
+ .config(function($stateProvider, $locationProvider) {
+ $stateProvider
+ .state('grades', {
+ url: '/grades',
+ templateUrl: 'views/grades.html',
+ controller: 'GradesCtrl',
+ controllerAs: 'gradesCtrl'
+ })
+ })
+
+ .factory('Feedback', [ '$http', function($http) {
+ return {
+ loadEntityStars: function(id, cb, cbErr) {
+ $http.get('/api/feedback/stars/' + id)
+ .success(cb)
+ .error(cbErr);
+ },
+ loadEntityStarsDimension: function(id, dimension, cb, cbErr) {
+ $http.get('/api/feedback/stars/' + id + '/dimension/' + dimension)
+ .success(cb)
+ .error(cbErr);
+ },
+ postEntityStarDimension: function(id, dimension, rating, cb, cbErr) {
+ $http.post('/api/feedback/stars/' + id + '/dimension/' + dimension,
+ {rating: rating})
+ .success(cb)
+ .error(cbErr);
+ },
+ loadMostRated: function(cb, cbErr) {
+ $http.get('/api/feedback/grades/most')
+ .success(cb)
+ .error(cbErr);
+ },
+ loadBestRated: function(cb, cbErr) {
+ $http.get('/api/feedback/grades/best')
+ .success(cb)
+ .error(cbErr);
+ },
+ loadWorstRated: function(cb, cbErr) {
+ $http.get('/api/feedback/grades/worst')
+ .success(cb)
+ .error(cbErr);
+ },
+ loadUsersRatings: function(cb, cbErr) {
+ $http.get('/api/feedback/grades/users')
+ .success(cb)
+ .error(cbErr);
+ },
+ }
+ }])
.controller('GradesCtrl', ['Feedback', '$scope', function(Feedback, $scope) {
(function() {
angular
- .module('index', ['model', 'ngSanitize'])
+ .module('index', [])
- .run(['$anchorScroll', function($anchorScroll) {
- $anchorScroll.yOffset = 80;
+ .config(function($stateProvider, $locationProvider) {
+ $stateProvider
+ .state('catalog', {
+ url: '/',
+ templateUrl: 'views/catalog/index.html',
+ controller: 'CatalogCtrl',
+ controllerAs: 'vm',
+ abstract: true
+ })
+ .state('catalog.highlighted', {
+ url: '',
+ templateUrl: 'views/catalog/highlighted.html',
+ controller: 'CatalogHighlightedCtrl',
+ controllerAs: 'vm'
+ })
+ .state('catalog.required', {
+ url: 'required',
+ templateUrl: 'views/catalog/most_required.html',
+ controller: 'CatalogRequiredCtrl',
+ controllerAs: 'vm'
+ })
+ .state('catalog.tags', {
+ url: 'tags',
+ templateUrl: 'views/catalog/by_tags.html',
+ controller: 'CatalogTagsCtrl',
+ controllerAs: 'vm'
+ })
+ })
+
+ .factory('Catalog', [ '$http', function($http) {
+ return {
+ loadHightlighted: function(cb, cbErr) {
+ $http.get('/api/catalog/highlighted')
+ .success(cb)
+ .error(cbErr);
+ },
+
+ loadMostRequired: function(cb, cbErr) {
+ $http.get('/api/catalog/required')
+ .success(cb)
+ .error(cbErr);
+ },
+
+ loadByTags: function(cb, cbErr) {
+ $http.get('/api/catalog/bytags')
+ .success(cb)
+ .error(cbErr);
+ },
+
+ loadStats: function(cb, cbErr) {
+ $http.get('/api/catalog/stats')
+ .success(cb)
+ .error(cbErr);
+ },
+
+ loadContributors: function(cb, cbErr) {
+ $http.get('/api/catalog/contributors')
+ .success(cb)
+ .error(cbErr);
+ },
+ }
}])
- .controller('IndexCtrl', ['Catalog', '$routeParams', '$sce', '$scope', '$location', '$anchorScroll', function(Catalog, $routeParams, $sce, $scope, $location, $anchorScroll) {
- this.loadHighlighted = function() {
- Catalog.loadHightlighted(
- function(data) {
- $scope.highlighted = data;
- }, function(err) {
- $scope.error = err;
- });
- };
+ .controller('CatalogCtrl', function(Catalog) {
+ var vm = this;
- this.loadMostRequired = function() {
- Catalog.loadMostRequired(
- function(data) {
- $scope.required = data;
- }, function(err) {
- $scope.error = err;
- });
- };
+ Catalog.loadContributors(
+ function(data) {
+ vm.contributors = data;
+ }, function(err) {
+ vm.error = err;
+ });
- this.loadByTags = function() {
- Catalog.loadByTags(
- function(data) {
- $scope.bytags = data;
- }, function(err) {
- $scope.error = err;
- });
- };
+ Catalog.loadStats(
+ function(data) {
+ vm.stats = data;
+ }, function(err) {
+ vm.error = err;
+ });
+ })
- this.loadStats = function() {
- Catalog.loadStats(
- function(data) {
- $scope.stats = data;
- }, function(err) {
- $scope.error = err;
- });
- };
+ .controller('CatalogHighlightedCtrl', function(Catalog) {
+ var vm = this;
- this.loadContributors = function() {
- Catalog.loadContributors(
- function(data) {
- $scope.contributors = data;
- }, function(err) {
- $scope.error = err;
- });
- };
+ Catalog.loadHightlighted(
+ function(data) {
+ vm.highlighted = data;
+ }, function(err) {
+ vm.error = err;
+ });
+ })
+ .controller('CatalogRequiredCtrl', function(Catalog) {
+ var vm = this;
- this.scrollTo = function(hash) {
- $anchorScroll(hash);
- }
+ Catalog.loadMostRequired(
+ function(data) {
+ vm.required = data;
+ }, function(err) {
+ vm.error = err;
+ });
+ })
+
+ .controller('CatalogTagsCtrl', function(Catalog, $anchorScroll, $location) {
+ var vm = this;
+
+ Catalog.loadByTags(
+ function(data) {
+ vm.bytags = data;
+ }, function(err) {
+ vm.error = err;
+ });
- this.loadHighlighted();
- this.loadStats();
- this.loadContributors();
- }])
- .directive('contributorList', ['Model', function(Model) {
+ vm.scrollTo = function(hash) {
+ $location.hash(hash);
+ $anchorScroll();
+ }
+ })
+
+ .directive('contributorList', function(Model) {
return {
restrict: 'E',
scope: {
},
templateUrl: '/directives/contributor-list.html'
};
- }])
+ })
})();
(function() {
angular
- .module('metrics', ['model'])
+ .module('metrics', [])
+
+ .factory('Metrics', [ '$http', function($http) {
+ return {
+ loadStructuralMetrics: function(id, cb, cbErr) {
+ $http.get('/api/metrics/structural/' + id)
+ .success(cb)
+ .error(cbErr);
+ }
+ }
+ }])
.directive('metricsList', function() {
return {
"content": [
{
"label": "Concrete classes",
- "value": $scope.chartMetrics.mnbcc.avg,
+ "value": $scope.chartMetrics.mnbcc?
+ $scope.chartMetrics.mnbcc.avg : 0,
"color": "#228835"
},
{
"label": "Abstract classes",
- "value": $scope.chartMetrics.mnbac.avg,
+ "value": $scope.chartMetrics.mnbac?
+ $scope.chartMetrics.mnbac.avg : 0,
"color": "#103EB8"
},
{
"label": "Interfaces",
- "value": $scope.chartMetrics.mnbic.avg,
+ "value": $scope.chartMetrics.mnbic?
+ $scope.chartMetrics.mnbic.avg : 0,
"color": "#e65314"
}
]
+++ /dev/null
-/*
- * Copyright 2016 Alexandre Terrasa <alexandre@moz-code.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.
- */
-
-(function() {
- var apiUrl = '/api';
-
- angular
- .module('model', [])
-
- .factory('Model', [ '$http', function($http) {
- return {
-
- loadEntity: function(id, cb, cbErr) {
- $http.get(apiUrl + '/entity/' + id)
- .success(cb)
- .error(cbErr);
- },
-
- loadEntityLinearization: function(id, cb, cbErr) {
- $http.get(apiUrl + '/linearization/' + id)
- .success(cb)
- .error(cbErr);
- },
-
- loadEntityDefs: function(id, cb, cbErr) {
- $http.get(apiUrl + '/defs/' + id)
- .success(cb)
- .error(cbErr);
- },
-
- loadEntityCode: function(id, cb, cbErr) {
- $http.get(apiUrl + '/code/' + id)
- .success(cb)
- .error(cbErr);
- },
-
- loadEntityGraph: function(id, cb, cbErr) {
- $http.get(apiUrl + '/graph/inheritance/' + id + '?cdepth=3')
- .success(cb)
- .error(cbErr);
- },
-
- search: function(q, n, cb, cbErr) {
- $http.get(apiUrl + '/search?q=' + q + '&n=' + n)
- .success(cb)
- .error(cbErr);
- }
- };
- }])
-
- .factory('Catalog', [ '$http', function($http) {
- return {
- loadHightlighted: function(cb, cbErr) {
- $http.get(apiUrl + '/catalog/highlighted')
- .success(cb)
- .error(cbErr);
- },
-
- loadMostRequired: function(cb, cbErr) {
- $http.get(apiUrl + '/catalog/required')
- .success(cb)
- .error(cbErr);
- },
-
- loadByTags: function(cb, cbErr) {
- $http.get(apiUrl + '/catalog/bytags')
- .success(cb)
- .error(cbErr);
- },
-
- loadStats: function(cb, cbErr) {
- $http.get(apiUrl + '/catalog/stats')
- .success(cb)
- .error(cbErr);
- },
-
- loadContributors: function(cb, cbErr) {
- $http.get(apiUrl + '/catalog/contributors')
- .success(cb)
- .error(cbErr);
- },
- }
- }])
-
- .factory('Feedback', [ '$http', function($http) {
- return {
- loadEntityStars: function(id, cb, cbErr) {
- $http.get(apiUrl + '/feedback/stars/' + id)
- .success(cb)
- .error(cbErr);
- },
- loadEntityStarsDimension: function(id, dimension, cb, cbErr) {
- $http.get(apiUrl + '/feedback/stars/' + id + '/dimension/' + dimension)
- .success(cb)
- .error(cbErr);
- },
- postEntityStarDimension: function(id, dimension, rating, cb, cbErr) {
- $http.post(apiUrl + '/feedback/stars/' + id + '/dimension/' + dimension,
- {rating: rating})
- .success(cb)
- .error(cbErr);
- },
- loadMostRated: function(cb, cbErr) {
- $http.get(apiUrl + '/feedback/grades/most')
- .success(cb)
- .error(cbErr);
- },
- loadBestRated: function(cb, cbErr) {
- $http.get(apiUrl + '/feedback/grades/best')
- .success(cb)
- .error(cbErr);
- },
- loadWorstRated: function(cb, cbErr) {
- $http.get(apiUrl + '/feedback/grades/worst')
- .success(cb)
- .error(cbErr);
- },
- loadUsersRatings: function(cb, cbErr) {
- $http.get(apiUrl + '/feedback/grades/users')
- .success(cb)
- .error(cbErr);
- },
- }
- }])
-
- .factory('DocDown', [ '$http', function($http) {
- return {
- postMarkdown: function(md, cb, cbErr) {
- $http.post(apiUrl + '/docdown', md)
- .success(cb)
- .error(cbErr);
- }
- }
- }])
-
- .factory('Metrics', [ '$http', function($http) {
- return {
- loadStructuralMetrics: function(id, cb, cbErr) {
- $http.get(apiUrl + '/metrics/structural/' + id)
- .success(cb)
- .error(cbErr);
- }
- }
- }])
-
- .factory('User', [ '$http', function($http) {
- return {
- loadUser: function(cb, cbErr) {
- $http.get(apiUrl + '/user')
- .success(cb)
- .error(cbErr);
- },
- loadUserStars: function(cb, cbErr) {
- $http.get(apiUrl + '/feedback/user/stars')
- .success(cb)
- .error(cbErr);
- },
- }
- }])
-})();
*/
(function() {
- angular.module('nitweb', ['ngRoute', 'ngSanitize', 'angular-loading-bar', 'entities', 'docdown', 'index', 'metrics', 'users', 'grades'])
+ angular.module('nitweb', ['ui.router', 'ngSanitize', 'angular-loading-bar', 'index', 'entities', 'docdown', 'metrics', 'users', 'grades'])
+
.config(['cfpLoadingBarProvider', function(cfpLoadingBarProvider) {
cfpLoadingBarProvider.includeSpinner = false;
}])
- .config(function($routeProvider, $locationProvider) {
- $routeProvider
- .when('/', {
- templateUrl: 'views/index.html',
- controller: 'IndexCtrl',
- controllerAs: 'indexCtrl'
- })
- .when('/user', {
- templateUrl: 'views/user.html',
- controller: 'UserCtrl',
- controllerAs: 'userCtrl'
- })
- .when('/docdown', {
- templateUrl: 'views/docdown.html',
- controller: 'DocdownCtrl',
- controllerAs: 'docdownCtrl'
- })
- .when('/grades', {
- templateUrl: 'views/grades.html',
- controller: 'GradesCtrl',
- controllerAs: 'gradesCtrl'
- })
- .when('/login', {
- controller : function(){
- window.location.replace('/login');
- },
- template : "<div></div>"
- })
- .when('/logout', {
- controller : function(){
- window.location.replace('/logout');
- },
- template : "<div></div>"
- })
- .when('/doc/:id', {
- templateUrl: 'views/doc.html',
- controller: 'EntityCtrl',
- controllerAs: 'entityCtrl',
- reloadOnSearch: false
- })
- .otherwise({
+
+ .run(['$anchorScroll', function($anchorScroll) {
+ $anchorScroll.yOffset = 80;
+ }])
+
+ .config(function($stateProvider, $locationProvider) {
+ $stateProvider
+ .state({
+ name: '404',
+ url: '*path',
templateUrl: 'views/error.html'
- });
+ })
$locationProvider.html5Mode(true);
})
-
- .filter('encodeURI', function() {
- return encodeURIComponent;
- });
})();
(function() {
angular
- .module('ui', [ 'model' ])
+ .module('ui', [])
- .controller('SearchCtrl', function(Model, $routeParams, $scope, $location, $document) {
+ .controller('SearchCtrl', function(Model, $scope, $location, $document) {
$scope.query = '';
(function() {
angular
- .module('users', ['ngSanitize', 'model'])
+ .module('users', ['ngSanitize'])
- .controller('UserCtrl', ['User', '$routeParams', '$scope', function(User, $routeParams, $scope) {
+ .config(function($stateProvider, $locationProvider) {
+ $stateProvider
+ .state('user', {
+ url: '/user',
+ templateUrl: 'views/user.html',
+ controller: 'UserCtrl',
+ controllerAs: 'userCtrl'
+ })
+ .state('login', {
+ url: '/login',
+ controller : function(){
+ window.location.replace('/login');
+ },
+ template : "<div></div>"
+ })
+ .state('logout', {
+ controller : function(){
+ window.location.replace('/logout');
+ },
+ template : "<div></div>"
+ })
+ })
+
+ .factory('User', [ '$http', function($http) {
+ return {
+ loadUser: function(cb, cbErr) {
+ $http.get('/api/user')
+ .success(cb)
+ .error(cbErr);
+ },
+ loadUserStars: function(cb, cbErr) {
+ $http.get('/api/feedback/user/stars')
+ .success(cb)
+ .error(cbErr);
+ },
+ }
+ }])
+
+ .controller('UserCtrl', ['User', '$scope', function(User, $scope) {
this.loadUser = function() {
User.loadUser(
function(data) {
--- /dev/null
+/*
+ * Copyright 2017 Alexandre Terrasa <alexandre@moz-code.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.
+ */
+
+/* cards */
+
+.card.active {
+ border: 1px solid #1E9431;
+}
+
+.card-heading {
+ margin-top: 0;
+ margin-bottom: 5px;
+}
+
+.card {
+ display: table;
+ width: 100%;
+ background: #fff;
+ border: 1px solid #ccc;
+ margin-top: 10px;
+ box-shadow: 0 -1px 0 #e5e5e5,0 0 2px rgba(0,0,0,.12),0 2px 4px rgba(0,0,0,.24);
+}
+
+.card-body, .card-left, .card-right {
+ display: table-cell;
+ padding: 15px;
+}
+
+.card-body {
+ padding: 15px 0;
+ width: 100%
+}
+
+.card-body:first-child {
+ padding-left: 15px;
+}
+
+.card-body:last-child {
+ padding-right: 15px;
+}
+
+.card-list {
+ margin-top: 10px;
+}
+
+.card-list > .card:first-child {
+ border-top: 1px solid #ccc;
+}
+
+.card-list > .card {
+ margin-top: 0;
+ border-top: none;
+}
+
+.card-title {
+ margin-top: 0;
+}
--- /dev/null
+/*
+ * Copyright 2017 Alexandre Terrasa <alexandre@moz-code.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.
+ */
+
+/*
+ * Code Highlighting
+ */
+
+.nitdoc h1, .nitdoc h2, .nitdoc h3, .nitdoc h4, .nitdoc h5, .nitdoc h6 {
+ color: #333;
+}
+
+.nitdoc .synopsys {
+ margin-top: 0;
+}
+
+.nitcode a { color: inherit; text-decoration: inherit; } /* hide links */
+.nitcode a:hover { text-decoration: underline; } /* underline links */
+.nitcode span[title]:hover { text-decoration: underline; } /* underline titles */
+/* lexical raw tokens. independent of usage or semantic: */
+.nitcode .nc_c { color: gray; font-style: italic; } /* comment */
+.nitcode .nc_d { color: #3D8127; font-style: italic; } /* documentation comments */
+.nitcode .nc_k { font-weight: bold; } /* keyword */
+.nitcode .nc_o {} /* operator */
+.nitcode .nc_i {} /* standard identifier */
+.nitcode .nc_t { color: #445588; font-weight: bold; } /* type/class identifier */
+.nitcode .nc_a { color: #445588; font-style: italic; } /* old style attribute identifier */
+.nitcode .nc_l { color: #009999; } /* char and number literal */
+.nitcode .nc_s { color: #8F1546; } /* string literal */
+/* syntactic token usage. added because of their position in the AST */
+.nitcode .nc_ast { color: blue; } /* assert label */
+.nitcode .nc_la { color: blue; } /* break/continue label */
+.nitcode .nc_m { color: #445588; } /* module name */
+/* syntactic groups */
+.nitcode .nc_def { font-weight: bold; color: blue; } /* name used in a definition */
+.nitcode .nc_def.nc_a { color: blue; } /* name used in a attribute definition */
+.nitcode .nc_def.nc_t { color: blue; } /* name used in a class or vt definition */
+.nitcode .nc_ss { color: #9E6BEB; } /* superstrings */
+.nitcode .nc_cdef {} /* A whole class definition */
+.nitcode .nc_pdef {} /* A whole property definition */
+/* semantic token usage */
+.nitcode .nc_v { font-style: italic; } /* local variable or parameter */
+.nitcode .nc_vt { font-style: italic; } /* virtual type or formal type */
+.nitcode .nc_error { border: 1px red solid;} /* not used */
+/*
+ * Copyright 2017 Alexandre Terrasa <alexandre@moz-code.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.
+ */
+
+/* utils */
+
+.no-margin {
+ margin: 0;
+}
+
+.no-padding {
+ padding: 0;
+}
+
+.navbar-fixed-top {
+ background-color: #1E9431;
+ box-shadow: 0 0 4px rgba(0,0,0,.14),0 4px 8px rgba(0,0,0,.28);
+}
+
+#loading-bar .bar {
+ background: #FF8100;
+}
+
/* Body */
body {
cursor: pointer;
}
-.nitdoc h1, .nitdoc h2, .nitdoc h3, .nitdoc h4, .nitdoc h5, .nitdoc h6 {
- color: #333;
-}
-
.page-header {
margin-top: 0;
border: none;
}
-/* cards */
-
-.card.active {
- border: 1px solid #1E9431;
-}
-
-.card-heading {
- margin-top: 0;
- margin-bottom: 5px;
-}
-
-.card {
- display: table;
- width: 100%;
- background: #fff;
- border: 1px solid #ccc;
- margin-top: 10px;
- box-shadow: 0 -1px 0 #e5e5e5,0 0 2px rgba(0,0,0,.12),0 2px 4px rgba(0,0,0,.24);
-}
-
-.card-body, .card-left, .card-right {
- display: table-cell;
- padding: 15px;
-}
-
-.card-body {
- padding: 15px 0;
- width: 100%
-}
-
-.card-body:first-child {
- padding-left: 15px;
-}
-
-.card-body:last-child {
- padding-right: 15px;
-}
-
-.card-list {
- margin-top: 10px;
-}
-
-.card-list > .card:first-child {
- border-top: 1px solid #ccc;
-}
-
-.card-list > .card {
- margin-top: 0;
- border-top: none;
-}
-
-.card-title {
- margin-top: 0;
-}
-
/* ui */
.btn-bar { margin-top: -5px; float: right }
cursor: pointer;
}
-/* loading bar */
-
-#loading-bar .bar {
- background: #FF8100;
-}
-
/* navs */
.nav-tabs li { cursor: pointer; }
-.navbar-fixed-top {
- background-color: #1E9431;
- box-shadow: 0 0 4px rgba(0,0,0,.14),0 4px 8px rgba(0,0,0,.28);
-}
-
-.navbar-fixed-top .form-control:hover, .navbar-fixed-top .form-control:focus {
- background: rgba(255, 255, 255, 0.2);
-}
-
-.navbar-fixed-top .form-control {
- background: rgba(255, 255, 255, 0.1);
- border: none;
- color: #fff;
- box-shadow: none;
-}
-
-.navbar-fixed-top .form-control-icon {
- color: #fff;
-}
-
-.navbar-fixed-top *::-webkit-input-placeholder {
- color: #fff;
-}
-.navbar-fixed-top *:-moz-placeholder {
- /* FF 4-18 */
- color: #fff;
-}
-.navbar-fixed-top *::-moz-placeholder {
- /* FF 19+ */
- color: #fff;
-}
-.navbar-fixed-top *:-ms-input-placeholder {
- /* IE 10+ */
- color: #fff;
-}
-
-.navbar-fixed-top .form-group {
- margin-top: 8px;
- margin-bottom: 0px;
-}
-
/* Summary */
.summary h1, .summary h2, .summary h3, .summary h4, .summary h5, .summary h6 {
.star.active {
color: #FFC000
}
-
-/*
- * Users
- */
-
-.avatar {
- border-radius: 2px;
-}
-
-.avatar-icon {
- width: 18px;
- height: 18px;
-}
-
-/*
- * Code Highlighting
- */
-
-.nitcode a { color: inherit; text-decoration: inherit; } /* hide links */
-.nitcode a:hover { text-decoration: underline; } /* underline links */
-.nitcode span[title]:hover { text-decoration: underline; } /* underline titles */
-/* lexical raw tokens. independent of usage or semantic: */
-.nitcode .nc_c { color: gray; font-style: italic; } /* comment */
-.nitcode .nc_d { color: #3D8127; font-style: italic; } /* documentation comments */
-.nitcode .nc_k { font-weight: bold; } /* keyword */
-.nitcode .nc_o {} /* operator */
-.nitcode .nc_i {} /* standard identifier */
-.nitcode .nc_t { color: #445588; font-weight: bold; } /* type/class identifier */
-.nitcode .nc_a { color: #445588; font-style: italic; } /* old style attribute identifier */
-.nitcode .nc_l { color: #009999; } /* char and number literal */
-.nitcode .nc_s { color: #8F1546; } /* string literal */
-/* syntactic token usage. added because of their position in the AST */
-.nitcode .nc_ast { color: blue; } /* assert label */
-.nitcode .nc_la { color: blue; } /* break/continue label */
-.nitcode .nc_m { color: #445588; } /* module name */
-/* syntactic groups */
-.nitcode .nc_def { font-weight: bold; color: blue; } /* name used in a definition */
-.nitcode .nc_def.nc_a { color: blue; } /* name used in a attribute definition */
-.nitcode .nc_def.nc_t { color: blue; } /* name used in a class or vt definition */
-.nitcode .nc_ss { color: #9E6BEB; } /* superstrings */
-.nitcode .nc_cdef {} /* A whole class definition */
-.nitcode .nc_pdef {} /* A whole property definition */
-/* semantic token usage */
-.nitcode .nc_v { font-style: italic; } /* local variable or parameter */
-.nitcode .nc_vt { font-style: italic; } /* virtual type or formal type */
-.nitcode .nc_error { border: 1px red solid;} /* not used */
margin-top: 20px;\r
margin-bottom: 20px;\r
border: 0;\r
- border-top: 1px solid #eeeeee;\r
+ border-top: 1px solid #ddd;\r
}\r
.sr-only {\r
position: absolute;\r
--- /dev/null
+/*
+ * Copyright 2017 Alexandre Terrasa <alexandre@moz-code.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.
+ */
+
+/* search */
+
+.has-icon {
+ position: relative;
+}
+
+.has-icon .form-control {
+ padding-left: 35px;
+}
+
+.form-control-icon {
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 2;
+ display: block;
+ width: 34px;
+ height: 34px;
+ line-height: 34px;
+ text-align: center;
+ pointer-events: none;
+}
+
+.navbar-fixed-top .form-control:hover, .navbar-fixed-top .form-control:focus {
+ background: rgba(255, 255, 255, 0.2);
+}
+
+.navbar-fixed-top .form-control {
+ background: rgba(255, 255, 255, 0.1);
+ border: none;
+ color: #fff;
+ box-shadow: none;
+}
+
+.navbar-fixed-top .form-control-icon {
+ color: #fff;
+}
+
+.navbar-fixed-top .form-group {
+ margin-top: 8px;
+ margin-bottom: 0px;
+}
+
+.navbar-fixed-top *::-webkit-input-placeholder { color: #fff; }
+.navbar-fixed-top *:-moz-placeholder { color: #fff; }
+.navbar-fixed-top *::-moz-placeholder { color: #fff; }
+.navbar-fixed-top *:-ms-input-placeholder { color: #fff; }
--- /dev/null
+<div>
+ <h3>Tags</h3>
+ <div class='container-fluid'>
+ <div class='col-xs-3' ng-repeat='(tag, packages) in vm.bytags'>
+ <span class='badge'>{{packages.length}}</span>
+ <a ng-click='vm.scrollTo(tag)'>{{tag}}</a>
+ </div>
+ </div>
+ <div ng-repeat='(tag, packages) in vm.bytags'>
+ <entity-list list-id='{{tag}}' list-title='{{tag}}'
+ list-entities='packages'
+ list-object-filter='{}' />
+ </div>
+</div>
--- /dev/null
+<div>
+ <entity-list list-title='Highlighted packages'
+ list-entities='vm.highlighted'
+ list-object-filter='{}' />
+</div>
--- /dev/null
+<div class='container-fluid'>
+ <div class='page-header'>
+ <h2>Welcome to NitWeb!</h2>
+ <p class='text-muted'>The Nit knowledge base.</p>
+ </div>
+
+ <ul class='nav nav-tabs' role='tablist'>
+ <li role='presentation' ui-sref-active='active'>
+ <a ui-sref='catalog.highlighted'>
+ <span class='glyphicon glyphicon-book'/> Highlighed
+ </a>
+ </li>
+ <li role='presentation' ui-sref-active='active'>
+ <a ui-sref='catalog.required'>
+ <span class='glyphicon glyphicon-book'/> Most required
+ </a>
+ </li>
+ <li role='presentation' ui-sref-active='active'>
+ <a ui-sref='catalog.tags'>
+ <span class='glyphicon glyphicon-book'/> By tags
+ </a>
+ </li>
+ </ul>
+ <table class='table'>
+ <tr>
+ <td ng-repeat='(key, value) in vm.stats'>
+ <h5><strong>{{value}}</strong> <span>{{key}}</span></h5>
+ </td>
+ </tr>
+ </table>
+
+ <div class='container-fluid'>
+ <div class='col-xs-9'>
+ <div class='tab-content'>
+ <div role='tabpanel' class='tab-pane fade in active'>
+ <ui-view />
+ </div>
+ </div>
+ </div>
+ <div class='col-xs-3'>
+ <contributor-list list-title='Maintainers'
+ list-contributors='vm.contributors.maintainers' />
+ <contributor-list list-title='Contributors'
+ list-contributors='vm.contributors.contributors' />
+ </div>
+ </div>
+</div>
--- /dev/null
+<div>
+ <entity-list list-title='Most required'
+ list-entities='vm.required'
+ list-object-filter='{}' />
+</div>
+++ /dev/null
-<ul class='nav nav-tabs'>
- <li role='presentation' class='active'>
- <a data-toggle='tab' data-target='#doc'>
- <span class='glyphicon glyphicon-book'/> Doc
- </a>
- </li>
- <li role='presentation'>
- <a data-toggle='tab' data-target='#graph' ng-click="entityCtrl.loadEntityGraph()">
- <span class='glyphicon glyphicon-object-align-vertical'/> Inheritance
- </a>
- </li>
- <li role='presentation'>
- <a data-toggle='tab' data-target='#all_props'>
- <span class='glyphicon glyphicon-tags'/> All properties
- </a>
- </li>
- <li role='presentation'>
- <a data-toggle='tab' role='tab' data-target='#linearization' aria-controls='linearization' ng-click='entityCtrl.loadEntityLinearization()'>
- <span class='glyphicon glyphicon-arrow-down'/> Linearization
- </a>
- </li>
- <li role='presentation'>
- <a data-toggle='tab' role='tab' data-target='#metrics' aria-controls='metrics' ng-click='entityCtrl.loadStructuralMetrics(); entityCtrl.loadPieChart()'>
- <span class='glyphicon glyphicon-stats'/> Metrics
- </a>
- </li>
-</ul>
-
-<div class='tab-content'>
- <div role='tabpanel' class='tab-pane fade in active' id='doc'>
- <div class='col-xs-3'>
- <ui-summary target='#summary-content' />
- </div>
- <div id='summary-content' class='col-xs-9'>
- <entity-card mentity='mentity' default-tab='doc' no-synopsis='true' />
-
- <entity-list list-title='Parents'
- list-entities='mentity.parents'
- list-object-filter='{}' />
-
- <entity-list list-title='Constructors'
- list-entities='mentity.all_mproperties'
- list-object-filter='{is_init: true}' />
-
- <entity-list list-title='Introduced properties'
- list-entities='mentity.intro_mproperties'
- list-object-filter='{is_init: "!true"}' />
-
- <entity-list list-title='Redefined properties'
- list-entities='mentity.redef_mproperties'
- list-object-filter='{is_init: "!true"}' />
- </div>
- </div>
- <div role='tabpanel' class='tab-pane fade' id='all_props'>
- <entity-list list-title='All properties' list-entities='mentity.all_mproperties'
- list-object-filter='{}' />
- </div>
- <div role='tabpanel' class='tab-pane fade' id='linearization'>
- <entity-linearization
- list-title='Class definitions'
- list-entities='linearization'
- list-focus='mentity.intro' />
- </div>
- <div role='tabpanel' class='tab-pane fade' id='graph'>
- <div class='card'>
- <div class='card-body text-center'>
- <entity-graph mentity='mentity' graph='graph' />
- </div>
- </div>
- </div>
- <div role='tabpanel' class='tab-pane fade' id='metrics'>
- <div class='card'>
- <div class='card-body container-fluid'>
- <h3 class='card-heading'>Class inheritance</h3>
- <div class='col-sm-6'>
- <h4>
- Inheritance kind
- <small>({{metrics.mclass['cnoa'].values[mentity.full_name].value}}
- ancestors)</small>
- </h4>
- <chart-class-inheritance-kind chart-id='chartInheritanceKind'
- chart-metrics='metrics.mclass' />
- </div>
- <div class='col-sm-6'>
- <h4>
- Inheritance metrics
- </h4>
- <dl class='dl-horizontal'>
- <dt>{{metrics.mclass.cnoa.values[mentity.full_name].value}}</dt>
- <dd>ancestors</dd>
- <dt>{{metrics.mclass.cnop.values[mentity.full_name].value}}</dt>
- <dd>direct parents</dd>
- <dt>{{metrics.mclass.cnoc.values[mentity.full_name].value}}</dt>
- <dd>direct children</dd>
- <dt>{{metrics.mclass.cnod.values[mentity.full_name].value}}</dt>
- <dd>descendants</dd>
- </dl>
- <dl class='dl-horizontal'>
- <dt>{{metrics.mclass.cdit.values[mentity.full_name].value}}</dt>
- <dd>Depth in Inheritance Tree</dd>
- </dl>
- </div>
- </div>
- </div>
- <div class='card'>
- <div class='card-body container-fluid'>
- <h3 class='card-heading'>Class properties</h3>
- <div class='col-sm-6'>
- <h4>
- Properties kind
- <small>({{metrics.mclass['cnbp'].values[mentity.full_name].value}}
- accessible properties)</small>
- </h4>
- <chart-class-properties-kind chart-id='chartPropertiesKind'
- chart-metrics='metrics.mclass' />
- </div>
- <div class='col-sm-6'>
- <h4>
- Properties inheritance
- <small>({{metrics.mclass['cnbp'].values[mentity.full_name].value}}
- accessible properties)</small>
- </h4>
- <chart-class-properties-inh chart-id='chartPropertiesInh'
- chart-metrics='metrics.mclass' />
- </div>
- </div>
- </div>
- </div>
-</div>
+++ /dev/null
-<ul class='nav nav-tabs' ng-init='entityCtrl.loadEntityLinearization()'>
- <li role='presentation' class='warning'>
- <a ng-href='{{mentity.mclass.web_url}}'>
- <span class='glyphicon glyphicon-chevron-left'/> Go to class
- </a>
- </li>
- <li role='presentation' class='active'>
- <a data-toggle='tab' role='tab' data-target='#linearization' aria-controls='linearization'>
- <span class='glyphicon glyphicon-arrow-down'/> Linearization
- </a>
- </li>
-</ul>
-
-<div class='tab-content'>
- <div role='tabpanel' class='tab-pane fade in active' id='linearization'>
- <entity-linearization
- list-title='Class definitions'
- list-entities='linearization'
- list-focus='mentity' />
- </div>
-</div>
--- /dev/null
+<div>
+ <entity-list list-title='All properties' list-entities='vm.mentity.all_mproperties'
+ list-object-filter='{}' />
+</div>
--- /dev/null
+<div class='card'>
+ <div class='card-body'>
+ <pre ng-bind-html='vm.code' />
+ <entity-location mentity='vm.mentity' />
+ </div>
+</div>
--- /dev/null
+<div>
+ <entity-list list-title='Class definitions'
+ list-entities='vm.defs' list-object-filter='{}' />
+</div>
--- /dev/null
+<div>
+ <div class='col-xs-3'>
+ <ui-summary target='#summary-content' />
+ </div>
+ <div class='col-xs-9' id='summary-content'>
+ <entity-card mentity='vm.mentity' default-tab='doc' no-synopsis='true' />
+
+ <entity-list list-title='Groups' list-entities='vm.mentity.mgroups'
+ list-object-filter='{}' />
+
+ <entity-list list-title='Parent group' list-entities='[vm.mentity.parent]'
+ list-object-filter='{}' ng-if='vm.mentity.parent' />
+
+ <entity-list list-title='Subgroups' list-entities='vm.mentity.mgroups'
+ list-object-filter='{}' />
+
+ <entity-list list-title='Modules' list-entities='vm.mentity.mmodules'
+ list-object-filter='{}' />
+
+ <entity-list list-title='Imported modules' list-entities='vm.mentity.imports'
+ list-object-filter='{}' />
+
+ <entity-list list-title='Introduced classes' list-entities='vm.mentity.intro_mclasses'
+ list-object-filter='{}' />
+
+ <entity-list list-title='Class redefinitions' list-entities='vm.mentity.redef_mclassdefs'
+ list-object-filter='{}' />
+
+ <entity-list list-title='Parents'
+ list-entities='vm.mentity.parents'
+ list-object-filter='{}' />
+
+ <entity-list list-title='Constructors'
+ list-entities='vm.mentity.all_mproperties'
+ list-object-filter='{is_init: true}' />
+
+ <entity-list list-title='Introduced properties'
+ list-entities='vm.mentity.intro_mproperties'
+ list-object-filter='{is_init: "!true"}' />
+
+ <entity-list list-title='Redefined properties'
+ list-entities='vm.mentity.redef_mproperties'
+ list-object-filter='{is_init: "!true"}' />
+
+ </div>
+</div>
--- /dev/null
+<div>
+ <ul class='nav nav-tabs' role='tablist'>
+
+ <!-- doc -->
+ <li role='presentation' ui-sref-active='active' ng-if='
+ vm.mentity.class_name == "MPackage" ||
+ vm.mentity.class_name == "MGroup" ||
+ vm.mentity.class_name == "MModule" ||
+ vm.mentity.class_name == "MClass" ||
+ vm.mentity.class_name == "MMethod" ||
+ vm.mentity.class_name == "MAttribute" ||
+ vm.mentity.class_name == "MVirtualTypeProp"'>
+ <a ui-sref='.doc'>
+ <span class='glyphicon glyphicon-book'/> Doc
+ </a>
+ </li>
+
+ <!-- graph -->
+ <li role='presentation' ui-sref-active='active' ng-if='
+ vm.mentity.class_name == "MPackage" ||
+ vm.mentity.class_name == "MGroup" ||
+ vm.mentity.class_name == "MModule" ||
+ vm.mentity.class_name == "MClass"'>
+ <a ui-sref='.graph'>
+ <span class='glyphicon glyphicon-object-align-vertical'/>
+ <span ng-if='vm.mentity.class_name == "MPackage"'>Dependencies</span>
+ <span ng-if='vm.mentity.class_name == "MGroup"'>Imports</span>
+ <span ng-if='vm.mentity.class_name == "MModule"'>Imports</span>
+ <span ng-if='vm.mentity.class_name == "MClass"'>Inheritance</span>
+ </a>
+ </li>
+
+ <!-- code -->
+ <li role='presentation' ui-sref-active='active' ng-if='
+ vm.mentity.class_name == "MModule"'>
+ <a ui-sref='.code'>
+ <span class='glyphicon glyphicon-console'/> Code
+ </a>
+ </li>
+
+ <!-- definitions -->
+ <li role='presentation' ui-sref-active='active' ng-if='
+ vm.mentity.class_name == "MModule"'>
+ <a ui-sref='.defs'>
+ <span class='glyphicon glyphicon-asterisk'/> Class definitions
+ </a>
+ </li>
+
+ <!-- all -->
+ <li role='presentation' ui-sref-active='active' ng-if='
+ vm.mentity.class_name == "MClass"'>
+ <a ui-sref='.all'>
+ <span class='glyphicon glyphicon-tags'/> All properties
+ </a>
+ </li>
+
+ <!-- linearization -->
+ <li role='presentation' ui-sref-active='active' ng-if='
+ vm.mentity.class_name == "MClass" ||
+ vm.mentity.class_name == "MMethod" ||
+ vm.mentity.class_name == "MAttribute" ||
+ vm.mentity.class_name == "MVirtualTypeProp"'>
+ <a ui-sref='.lin'>
+ <span class='glyphicon glyphicon-arrow-down'/> Linearization
+ </a>
+ </li>
+
+ <!-- metrics -->
+ <li role='presentation' ui-sref-active='active' ng-if='
+ vm.mentity.class_name == "MPackage" ||
+ vm.mentity.class_name == "MGroup" ||
+ vm.mentity.class_name == "MModule" ||
+ vm.mentity.class_name == "MClass"'>
+ <a ui-sref='.metrics'>
+ <span class='glyphicon glyphicon-stats'/> Metrics
+ </a>
+ </li>
+ </ul>
+ <br>
+ <ui-view />
+</div>
--- /dev/null
+<div class='card'>
+ <div class='card-body text-center'>
+ <entity-graph mentity='mentity' graph='vm.graph' />
+ </div>
+</div>
--- /dev/null
+<div class='container-fluid'>
+
+ <div ng-if='vm.error' class='alert alert-danger' role='alert'>
+ <span class='glyphicon glyphicon-exclamation-sign' aria-hidden='true'></span>
+ <span class='sr-only'>Error:</span>
+ <span ng-switch='vm.error.status'>
+ <span ng-switch-when='404'>Entity <code>{{vm.entityId}}</code> not found!</span>
+ <span ng-switch-default>An error occured<br/>{{vm.error.status}}: {{vm.error.message}}</span>
+ </span>
+ </div>
+
+ <div class='page-header'>
+ <h2><entity-signature mentity='vm.mentity' /></h2>
+ <entity-namespace namespace='vm.mentity.namespace' />
+ </div>
+
+ <ui-view />
+</div>
--- /dev/null
+<div>
+ <entity-linearization
+ list-title='Class definitions'
+ list-entities='vm.linearization'
+ list-focus='vm.focus' />
+</div>
--- /dev/null
+<div id='metrics'>
+
+ <!-- packages, groups -->
+
+ <metrics-list
+ ng-if='vm.mentity.class_name == "MPackage" || vm.mentity.class_name == "MGroup"'
+ list-id='modules_importation'
+ list-title='Modules importation'
+ list-metrics='vm.metrics.mmodules'
+ list-metrics-names='["mdit", "mnoa", "mnop", "mnoc", "mnod"]'
+ list-metrics-default='"mdit"' />
+ <metrics-list
+ ng-if='vm.mentity.class_name == "MPackage" || vm.mentity.class_name == "MGroup"'
+ list-id='modules_definitions'
+ list-title='Modules content'
+ list-metrics='vm.metrics.mmodules'
+ list-metrics-names='["mnbi", "mnbr", "mnbic", "mnbac", "mnbcc"]'
+ list-metrics-default='"mnbi"' />
+ <metrics-list
+ ng-if='vm.mentity.class_name == "MPackage" || vm.mentity.class_name == "MGroup"'
+ list-id='classes_inheritance'
+ list-title='Classes inheritance'
+ list-metrics='vm.metrics.mclasses'
+ list-metrics-names='["cdit", "cnoa", "cnop", "cnoc", "cnod"]'
+ list-metrics-default='"cdit"' />
+ <metrics-list
+ ng-if='vm.mentity.class_name == "MPackage" || vm.mentity.class_name == "MGroup"'
+ list-id='classes_properties'
+ list-title='Classes properties'
+ list-metrics='vm.metrics.mclasses'
+ list-metrics-names='["cnbp", "cnba", "cnbip", "cnbrp", "cnbhp", "cnblp"]'
+ list-metrics-default='"cnbp"' />
+
+ <!-- module -->
+
+ <div class='card' ng-if='vm.mentity.class_name == "MModule"'>
+ <div class='card-body container-fluid'>
+ <h3 class='card-heading'>Module importation</h3>
+ <div class='col-sm-6'>
+ <h4>
+ Importation metrics
+ </h4>
+ <dl class='dl-horizontal'>
+ <dt>{{vm.metrics.mmodule.mnoa.values[vm.mentity.full_name].value}}</dt>
+ <dd>ancestors</dd>
+ <dt>{{vm.metrics.mmodule.mnop.values[vm.mentity.full_name].value}}</dt>
+ <dd>direct parents</dd>
+ <dt>{{vm.metrics.mmodule.mnoc.values[vm.mentity.full_name].value}}</dt>
+ <dd>direct children</dd>
+ <dt>{{vm.metrics.mmodule.mnod.values[vm.mentity.full_name].value}}</dt>
+ <dd>descendants</dd>
+ </dl>
+ <dl class='dl-horizontal'>
+ <dt>{{vm.metrics.mmodule.mdit.values[vm.mentity.full_name].value}}</dt>
+ <dd>Depth in Inheritance Tree</dd>
+ </dl>
+ </div>
+ </div>
+ </div>
+ <div class='card' ng-if='vm.mentity.class_name == "MModule"'>
+ <div class='card-body container-fluid'>
+ <h3 class='card-heading'>Module definitions</h3>
+ <div class='col-sm-6'>
+ <h4>
+ Class definition kinds
+ <small>({{vm.metrics.mmodule['mnbi'].values[vm.mentity.full_name].value +
+ vm.metrics.mclass['mnbc'].values[vm.mentity.full_name].value}}
+ class definitions)</small>
+ </h4>
+ <chart-module-definitions-kind chart-id='chartDefinitionsKind'
+ chart-metrics='vm.metrics.mmodule' />
+ </div>
+ <div class='col-sm-6'>
+ <h4>
+ Class definition inheritance
+ <small>({{vm.metrics.mmodule['mnbd'].values[vm.mentity.full_name].value}}
+ accessible definitions)</small>
+ </h4>
+ <chart-module-definitions-inh chart-id='chartDefinitionsInh'
+ chart-metrics='vm.metrics.mmodule' />
+ </div>
+ </div>
+ </div>
+ <metrics-list
+ ng-if='vm.mentity.class_name == "MModule"'
+ list-id='classes_inheritance'
+ list-title='Classes inheritance'
+ list-metrics='vm.metrics.mclasses'
+ list-metrics-names='["cdit", "cnoa", "cnop", "cnoc", "cnod"]'
+ list-metrics-default='"cdit"' />
+ <metrics-list
+ ng-if='vm.mentity.class_name == "MModule"'
+ list-id='classes_properties'
+ list-title='Classes properties'
+ list-metrics='vm.metrics.mclasses'
+ list-metrics-names='["cnbp", "cnba", "cnbip", "cnbrp", "cnbhp", "cnblp"]'
+ list-metrics-default='"cnbp"' />
+
+ <!-- mclass -->
+
+ <div class='card' ng-if='vm.mentity.class_name == "MClass"'>
+ <div class='card-body container-fluid'>
+ <h3 class='card-heading'>Class inheritance</h3>
+ <div class='col-sm-6'>
+ <h4>
+ Inheritance kind
+ <small>({{vm.metrics.mclass['cnoa'].values[vm.mentity.full_name].value}}
+ ancestors)</small>
+ </h4>
+ <chart-class-inheritance-kind chart-id='chartInheritanceKind'
+ chart-metrics='vm.metrics.mclass' />
+ </div>
+ <div class='col-sm-6'>
+ <h4>
+ Inheritance metrics
+ </h4>
+ <dl class='dl-horizontal'>
+ <dt>{{vm.metrics.mclass.cnoa.values[vm.mentity.full_name].value}}</dt>
+ <dd>ancestors</dd>
+ <dt>{{vm.metrics.mclass.cnop.values[vm.mentity.full_name].value}}</dt>
+ <dd>direct parents</dd>
+ <dt>{{vm.metrics.mclass.cnoc.values[vm.mentity.full_name].value}}</dt>
+ <dd>direct children</dd>
+ <dt>{{vm.metrics.mclass.cnod.values[vm.mentity.full_name].value}}</dt>
+ <dd>descendants</dd>
+ </dl>
+ <dl class='dl-horizontal'>
+ <dt>{{vm.metrics.mclass.cdit.values[vm.mentity.full_name].value}}</dt>
+ <dd>Depth in Inheritance Tree</dd>
+ </dl>
+ </div>
+ </div>
+ </div>
+ <div class='card' ng-if='vm.mentity.class_name == "MClass"'>
+ <div class='card-body container-fluid'>
+ <h3 class='card-heading'>Class properties</h3>
+ <div class='col-sm-6'>
+ <h4>
+ Properties kind
+ <small>({{vm.metrics.mclass['cnbp'].values[vm.mentity.full_name].value}}
+ accessible properties)</small>
+ </h4>
+ <chart-class-properties-kind chart-id='chartPropertiesKind'
+ chart-metrics='vm.metrics.mclass' />
+ </div>
+ <div class='col-sm-6'>
+ <h4>
+ Properties inheritance
+ <small>({{vm.metrics.mclass['cnbp'].values[vm.mentity.full_name].value}}
+ accessible properties)</small>
+ </h4>
+ <chart-class-properties-inh chart-id='chartPropertiesInh'
+ chart-metrics='vm.metrics.mclass' />
+ </div>
+ </div>
+ </div>
+</div>
+++ /dev/null
-<ul class='nav nav-tabs'>
- <li class='active'>
- <a data-toggle='tab' data-target='#doc'>
- <span class='glyphicon glyphicon-book'/> Doc
- </a>
- </li>
- <li role='presentation'>
- <a data-toggle='tab' data-target='#graph' ng-click="entityCtrl.loadEntityGraph()">
- <span class='glyphicon glyphicon-object-align-vertical'/> Imports
- </a>
- </li>
- <li role='presentation'>
- <a data-toggle='tab' role='tab' data-target='#metrics' aria-controls='metrics' ng-click='entityCtrl.loadStructuralMetrics()'>
- <span class='glyphicon glyphicon-stats'/> Metrics
- </a>
- </li>
-</ul>
-
-<div class='tab-content'>
- <div role='tabpanel' class='tab-pane fade in active' id='doc'>
- <div class='col-xs-3'>
- <ui-summary target='#summary-content' />
- </div>
- <div class='col-xs-9' id='summary-content'>
- <entity-card mentity='mentity' default-tab='doc' no-synopsis='true' />
-
- <entity-list list-title='Parent group' list-entities='[mentity.parent]'
- list-object-filter='{}' ng-if='mentity.parent' />
-
- <entity-list list-title='Subgroups' list-entities='mentity.mgroups'
- list-object-filter='{}' />
-
- <entity-list list-title='Modules' list-entities='mentity.mmodules'
- list-object-filter='{}' />
- </div>
- </div>
- <div role='tabpanel' class='tab-pane fade' id='graph'>
- <div class='card'>
- <div class='card-body text-center'>
- <entity-graph mentity='mentity' graph='graph' />
- </div>
- </div>
- </div>
- <div role='tabpanel' class='tab-pane fade' id='metrics'>
- <metrics-list
- list-id='modules_importation'
- list-title='Modules importation'
- list-metrics='metrics.mmodules'
- list-metrics-names='["mdit", "mnoa", "mnop", "mnoc", "mnod"]'
- list-metrics-default='"mdit"' />
- <metrics-list
- list-id='modules_definitions'
- list-title='Modules content'
- list-metrics='metrics.mmodules'
- list-metrics-names='["mnbi", "mnbr", "mnbic", "mnbac", "mnbcc"]'
- list-metrics-default='"mnbi"' />
- <metrics-list
- list-id='classes_inheritance'
- list-title='Classes inheritance'
- list-metrics='metrics.mclasses'
- list-metrics-names='["cdit", "cnoa", "cnop", "cnoc", "cnod"]'
- list-metrics-default='"cdit"' />
- <metrics-list
- list-id='classes_properties'
- list-title='Classes properties'
- list-metrics='metrics.mclasses'
- list-metrics-names='["cnbp", "cnba", "cnbip", "cnbrp", "cnbhp", "cnblp"]'
- list-metrics-default='"cnbp"' />
- </div>
-</div>
+++ /dev/null
-<div class='container-fluid'>
- <div class='page-header'>
- <h2>Welcome to NitWeb!</h2>
- <p class='text-muted'>The Nit knowledge base.</p>
- </div>
-
- <ul class='nav nav-tabs' role='tablist'>
- <li role='presentation' class='active'>
- <a data-toggle='tab' role='tab' data-target='#highlighted' aria-controls='highlighted'>
- <span class='glyphicon glyphicon-book'/> Highlighed
- </a>
- </li>
- <li role='presentation'>
- <a data-toggle='tab' role='tab' data-target='#required' aria-controls='required'
- ng-click='indexCtrl.loadMostRequired()'>
- <span class='glyphicon glyphicon-book'/> Most required
- </a>
- </li>
- <li role='presentation'>
- <a data-toggle='tab' role='tab' data-target='#bytags' aria-controls='bytags'
- ng-click='indexCtrl.loadByTags()'>
- <span class='glyphicon glyphicon-book'/> By tags
- </a>
- </li>
- </ul>
- <table class='table'>
- <tr>
- <td ng-repeat='(key, value) in stats'>
- <h5><strong>{{value}}</strong> <span>{{key}}</span></h5>
- </td>
- </tr>
- </table>
-
- <div class='container-fluid'>
- <div class='col-xs-9'>
- <div class='tab-content'>
- <div role='tabpanel' class='tab-pane fade in active' id='highlighted'>
- <entity-list list-title='Highlighted packages'
- list-entities='highlighted'
- list-object-filter='{}' />
- </div>
- <div role='tabpanel' class='tab-pane fade' id='required'>
- <entity-list list-title='Most required'
- list-entities='required'
- list-object-filter='{}' />
- </div>
- <div role='tabpanel' class='tab-pane fade' id='bytags'>
- <h3>Tags</h3>
- <div class='container-fluid'>
- <div class='col-xs-3' ng-repeat='(tag, packages) in bytags'>
- <span class='badge'>{{packages.length}}</span>
- <a ng-click='indexCtrl.scrollTo(tag)'>{{tag}}</a>
- </div>
- </div>
- <div ng-repeat='(tag, packages) in bytags'>
- <entity-list list-id='{{tag}}' list-title='{{tag}}'
- list-entities='packages'
- list-object-filter='{}' />
- </div>
- </div>
- </div>
- </div>
- <div class='col-xs-3'>
- <contributor-list list-title='Maintainers'
- list-contributors='contributors.maintainers' />
- <contributor-list list-title='Contributors'
- list-contributors='contributors.contributors' />
- </div>
- </div>
-</div>
+++ /dev/null
-<ul class='nav nav-tabs'>
- <li role='presentation' class='active'>
- <a data-toggle='tab' data-target='#doc'>
- <span class='glyphicon glyphicon-book'/> Doc
- </a>
- </li>
- <li role='presentation'>
- <a data-toggle='tab' data-target='#graph' ng-click="entityCtrl.loadEntityGraph()">
- <span class='glyphicon glyphicon-object-align-vertical'/> Imports
- </a>
- </li>
- <li role='presentation'>
- <a data-toggle='tab' data-target='#code' ng-click="entityCtrl.loadEntityCode()">
- <span class='glyphicon glyphicon-console'/> Code
- </a>
- </li>
- <li role='presentation'>
- <a data-toggle='tab' data-target='#defs' ng-click="entityCtrl.loadEntityDefs()">
- <span class='glyphicon glyphicon-asterisk'/> Class definitions
- </a>
- </li>
- <li role='presentation'>
- <a data-toggle='tab' role='tab' data-target='#metrics' aria-controls='metrics' ng-click='entityCtrl.loadStructuralMetrics()'>
- <span class='glyphicon glyphicon-stats'/> Metrics
- </a>
- </li>
-</ul>
-
-<div class='tab-content'>
- <div role='tabpanel' class='tab-pane fade in active' id='doc'>
- <div class='col-xs-3'>
- <ui-summary target='#summary-content' />
- </div>
- <div class='col-xs-9' id='summary-content'>
- <entity-card mentity='mentity' default-tab='doc' no-synopsis='true' />
-
- <entity-list list-title='Imported modules' list-entities='mentity.imports'
- list-object-filter='{}' />
-
- <entity-list list-title='Introduced classes' list-entities='mentity.intro_mclasses'
- list-object-filter='{}' />
-
- <entity-list list-title='Class redefinitions' list-entities='mentity.redef_mclassdefs'
- list-object-filter='{}' />
- </div>
- </div>
- <div role='tabpanel' class='tab-pane fade' id='code'>
- <div class='card'>
- <div class='card-body'>
- <pre ng-bind-html='code' />
- <entity-location mentity='mentity' />
- </div>
- </div>
- </div>
- <div role='tabpanel' class='tab-pane fade' id='defs'>
- <entity-list list-title='Class definitions' list-entities='defs'
- list-object-filter='{}' />
- </div>
- <div class='tab-pane fade' id='graph'>
- <div class='card'>
- <div class='card-body text-center'>
- <entity-graph mentity='mentity' graph='graph' />
- </div>
- </div>
- </div>
- <div role='tabpanel' class='tab-pane fade' id='metrics'>
- <div class='card'>
- <div class='card-body container-fluid'>
- <h3 class='card-heading'>Module importation</h3>
- <div class='col-sm-6'>
- <h4>
- Importation metrics
- </h4>
- <dl class='dl-horizontal'>
- <dt>{{metrics.mmodule.mnoa.values[mentity.full_name].value}}</dt>
- <dd>ancestors</dd>
- <dt>{{metrics.mmodule.mnop.values[mentity.full_name].value}}</dt>
- <dd>direct parents</dd>
- <dt>{{metrics.mmodule.mnoc.values[mentity.full_name].value}}</dt>
- <dd>direct children</dd>
- <dt>{{metrics.mmodule.mnod.values[mentity.full_name].value}}</dt>
- <dd>descendants</dd>
- </dl>
- <dl class='dl-horizontal'>
- <dt>{{metrics.mmodule.mdit.values[mentity.full_name].value}}</dt>
- <dd>Depth in Inheritance Tree</dd>
- </dl>
- </div>
- </div>
- </div>
- <div class='card'>
- <div class='card-body container-fluid'>
- <h3 class='card-heading'>Module definitions</h3>
- <div class='col-sm-6'>
- <h4>
- Class definition kinds
- <small>({{metrics.mmodule['mnbi'].values[mentity.full_name].value +
- metrics.mclass['mnbc'].values[mentity.full_name].value}}
- class definitions)</small>
- </h4>
- <chart-module-definitions-kind chart-id='chartDefinitionsKind'
- chart-metrics='metrics.mmodule' />
- </div>
- <div class='col-sm-6'>
- <h4>
- Class definition inheritance
- <small>({{metrics.mmodule['mnbd'].values[mentity.full_name].value}}
- accessible definitions)</small>
- </h4>
- <chart-module-definitions-inh chart-id='chartDefinitionsInh'
- chart-metrics='metrics.mmodule' />
- </div>
- </div>
- </div>
- <metrics-list
- list-id='classes_inheritance'
- list-title='Classes inheritance'
- list-metrics='metrics.mclasses'
- list-metrics-names='["cdit", "cnoa", "cnop", "cnoc", "cnod"]'
- list-metrics-default='"cdit"' />
- <metrics-list
- list-id='classes_properties'
- list-title='Classes properties'
- list-metrics='metrics.mclasses'
- list-metrics-names='["cnbp", "cnba", "cnbip", "cnbrp", "cnbhp", "cnblp"]'
- list-metrics-default='"cnbp"' />
- </div>
-</div>
+++ /dev/null
-<ul class='nav nav-tabs' role='tablist'>
- <li role='presentation' class='active'>
- <a data-toggle='tab' role='tab' data-target='#doc' aria-controls="doc">
- <span class='glyphicon glyphicon-book'/> Doc
- </a>
- </li>
- <li role='presentation'>
- <a data-toggle='tab' data-target='#graph' ng-click="entityCtrl.loadEntityGraph()">
- <span class='glyphicon glyphicon-object-align-vertical'/> Dependencies
- </a>
- </li>
- <li role='presentation'>
- <a data-toggle='tab' role='tab' data-target='#metrics' aria-controls='metrics' ng-click='entityCtrl.loadStructuralMetrics()'>
- <span class='glyphicon glyphicon-stats'/> Metrics
- </a>
- </li>
-</ul>
-
-<div class='tab-content'>
- <div role='tabpanel' class='tab-pane fade in active' id='doc'>
- <div class='col-xs-3'>
- <ui-summary target='#summary-content' />
- </div>
- <div class='col-xs-9' id='summary-content'>
- <entity-card mentity='mentity' default-tab='doc' no-synopsis='true' />
-
- <entity-list list-title='Groups' list-entities='mentity.mgroups'
- list-object-filter='{}' />
- </div>
- </div>
- <div role='tabpanel' class='tab-pane fade' id='graph'>
- <div class='card'>
- <div class='card-body text-center'>
- <entity-graph mentity='mentity' graph='graph' />
- </div>
- </div>
- </div>
- <div role='tabpanel' class='tab-pane fade' id='metrics'>
- <metrics-list
- list-id='modules_importation'
- list-title='Modules importation'
- list-metrics='metrics.mmodules'
- list-metrics-names='["mdit", "mnoa", "mnop", "mnoc", "mnod"]'
- list-metrics-default='"mdit"' />
- <metrics-list
- list-id='modules_definitions'
- list-title='Modules content'
- list-metrics='metrics.mmodules'
- list-metrics-names='["mnbi", "mnbr", "mnbic", "mnbac", "mnbcc"]'
- list-metrics-default='"mnbi"' />
- <metrics-list
- list-id='classes_inheritance'
- list-title='Classes inheritance'
- list-metrics='metrics.mclasses'
- list-metrics-names='["cdit", "cnoa", "cnop", "cnoc", "cnod"]'
- list-metrics-default='"cdit"' />
- <metrics-list
- list-id='classes_properties'
- list-title='Classes properties'
- list-metrics='metrics.mclasses'
- list-metrics-names='["cnbp", "cnba", "cnbip", "cnbrp", "cnbhp", "cnblp"]'
- list-metrics-default='"cnbp"' />
- </div>
-</div>
+++ /dev/null
-<ul class='nav nav-tabs' ng-init='entityCtrl.loadEntityLinearization()'>
- <li role='presentation' class='warning'>
- <a href='{{mentity.mproperty.web_url}}'>
- <span class='glyphicon glyphicon-chevron-left'/> Go to property
- </a>
- </li>
- <li role='presentation' class='active'>
- <a data-toggle='tab' role='tab' data-target='#linearization' aria-controls='linearization'>
- <span class='glyphicon glyphicon-arrow-down'/> Linearization
- </a>
- </li>
-</ul>
-
-<div class='tab-content'>
- <div role='tabpanel' class='tab-pane fade in active' id='linearization'>
- <entity-linearization
- list-title='Class definitions'
- list-entities='linearization'
- list-focus='mentity' />
- </div>
-</div>
+++ /dev/null
-<ul class='nav nav-tabs'>
- <li role='presentation' class='active'>
- <a data-toggle='tab' data-target='#doc'>
- <span class='glyphicon glyphicon-book'/> Doc
- </a>
- </li>
- <li role='presentation'>
- <a data-toggle='tab' role='tab' data-target='#linearization' aria-controls='linearization' ng-click='entityCtrl.loadEntityLinearization()'>
- <span class='glyphicon glyphicon-arrow-down'/> Linearization
- </a>
- </li>
-</ul>
-
-<div class='tab-content'>
- <div role='tabpanel' class='tab-pane fade in active' id='doc'>
- <div class='col-xs-3'>
- <ui-summary target='#summary-content' />
- </div>
- <div class='col-xs-9' id='summary-content'>
- <entity-card mentity='mentity' default-tab='doc' no-synopsis='true' />
- </div>
- </div>
- <div role='tabpanel' class='tab-pane fade' id='linearization'>
- <entity-linearization
- list-title='Class definitions'
- list-entities='linearization'
- list-focus='mentity.intro' />
- </div>
-</div>
var debug = toolcontext.opt_debug.value
makefile.write """
-CC ?= ccache cc
-CXX ?= ccache c++
+ifeq ($(origin CC), default)
+ CC = ccache cc
+endif
+ifeq ($(origin CXX), default)
+ CXX = ccache c++
+endif
CFLAGS ?= -g {{{if not debug then "-O2" else ""}}} -Wno-unused-value -Wno-switch -Wno-attributes -Wno-trigraphs
CINCL =
LDFLAGS ?=
--- /dev/null
+# 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.
+# Detect the code smells and antipatterns in the code.
+
+module codesmells_metrics
+
+import frontend
+import metrics_base
+import mclasses_metrics
+import semantize
+import method_analyze_metrics
+import mclassdef_collect
+
+redef class ToolContext
+ var codesmells_metrics_phase = new CodeSmellsMetricsPhase(self, null)
+end
+
+class CodeSmellsMetricsPhase
+ super Phase
+ var average_number_of_lines = 0.0
+ var average_number_of_parameter = 0.0
+ var average_number_of_method = 0.0
+ var average_number_of_attribute = 0.0
+
+ redef fun process_mainmodule(mainmodule, given_mmodules) do
+ print toolcontext.format_h1("--- Code Smells Metrics ---")
+ self.set_all_average_metrics
+ var mclass_codesmell = new BadConceptonController
+ var collect = new Counter[MClassDef]
+ var mclassdefs = new Array[MClassDef]
+
+ for mclass in mainmodule.flatten_mclass_hierarchy do
+ mclass_codesmell.collect(mclass.mclassdefs,self)
+ end
+ mclass_codesmell.print_top(10)
+ end
+
+ fun set_all_average_metrics do
+ var model_builder = toolcontext.modelbuilder
+ var model_view = model_builder.model.private_view
+ self.average_number_of_lines = model_view.get_avg_linenumber(model_builder)
+ self.average_number_of_parameter = model_view.get_avg_parameter
+ self.average_number_of_method = model_view.get_avg_method
+ self.average_number_of_attribute = model_view.get_avg_attribut
+ end
+end
+
+class BadConceptonController
+ # Code smell list
+ var bad_conception_elements = new Array[BadConceptionFinder]
+
+ # Print all element conception
+ fun print_all do
+ for bad_conception in bad_conception_elements do
+ bad_conception.print_all
+ end
+ end
+
+ # Print number of top element conception
+ fun print_top(number: Int) do
+ var test = self.get_numbers_of_elements(number)
+ for bad_conception in test do
+ bad_conception.print_all
+ end
+ end
+
+ # Collection
+ fun collect(mclassdefs: Array[MClassDef],phase: CodeSmellsMetricsPhase) do
+ for mclassdef in mclassdefs do
+ var bad_conception_class = new BadConceptionFinder(mclassdef,phase)
+ bad_conception_class.collect
+ bad_conception_elements.add(bad_conception_class)
+ end
+ end
+
+ fun sort: Array[BadConceptionFinder]
+ do
+ var res = bad_conception_elements
+ var sorter = new BadConceptionComparator
+ sorter.sort(res)
+ return res
+ end
+
+ fun get_numbers_of_elements(number : Int) : Array[BadConceptionFinder]do
+ var return_values = new Array[BadConceptionFinder]
+ var list = self.sort
+ var min = number
+ if list.length <= number*2 then min = list.length
+ for i in [0..min[ do
+ var t = list[list.length-i-1]
+ return_values.add(t)
+ end
+ return return_values
+ end
+end
+
+class BadConceptionFinder
+ var mclassdef: MClassDef
+ var array_badconception = new Array[BadConception]
+ var phase: CodeSmellsMetricsPhase
+
+ fun collect do
+ var bad_conception_elements = new Array[BadConception]
+ bad_conception_elements.add(new LargeClass(phase))
+ bad_conception_elements.add(new LongParameterList(phase))
+ bad_conception_elements.add(new FeatureEnvy(phase))
+ bad_conception_elements.add(new LongMethod(phase))
+ for bad_conception_element in bad_conception_elements do
+ if bad_conception_element.collect(self.mclassdef,phase.toolcontext.modelbuilder) == true then array_badconception.add(bad_conception_element)
+ end
+ end
+
+ fun print_all do
+ if array_badconception.length != 0 then
+ print "-----------"
+ print "{mclassdef.full_name}"
+ for bad_conception in array_badconception do
+ bad_conception.print_result
+ end
+ end
+ end
+end
+
+class BadConception
+ var phase: CodeSmellsMetricsPhase
+
+ # Name
+ fun name: String is abstract
+
+ # Description
+ fun desc: String is abstract
+
+ # Collection method
+ fun collect(mclassdef: MClassDef, model_builder: ModelBuilder): Bool is abstract
+
+ # Show results in console
+ fun print_result is abstract
+end
+
+class LargeClass
+ super BadConception
+ var number_attribut = 0
+
+ var number_method = 0
+
+ redef fun name do return "LARGC"
+
+ redef fun desc do return "Large class"
+
+ redef fun collect(mclassdef, model_builder): Bool do
+ number_attribut = mclassdef.collect_intro_and_redef_mattributes(model_builder.model.private_view).length
+ # get the number of methods (subtract the get and set of attibutes with (numberAtribut*2))
+ number_method = mclassdef.collect_intro_and_redef_methods(model_builder.model.private_view).length
+ return number_method.to_f > phase.average_number_of_method and number_attribut.to_f > phase.average_number_of_attribute
+ end
+
+ redef fun print_result do
+ print phase.toolcontext.format_h2("{desc}: {number_attribut} attributes and {number_method} methods ({phase.average_number_of_attribute}A {phase.average_number_of_method}M Average)")
+ end
+end
+
+class LongParameterList
+ super BadConception
+ var bad_methods = new Array[MMethodDef]
+
+ redef fun name do return "LONGPL"
+
+ redef fun desc do return "Long parameter list"
+
+ redef fun collect(mclassdef, model_builder): Bool do
+ for meth in mclassdef.collect_intro_and_redef_mpropdefs(model_builder.model.private_view) do
+ # check if the property is a method definition
+ if not meth isa MMethodDef then continue
+ # Check if method has a signature
+ if meth.msignature == null then continue
+ if meth.msignature.mparameters.length <= 4 then continue
+ bad_methods.add(meth)
+ end
+ return bad_methods.not_empty
+ end
+
+
+ redef fun print_result do
+ print "{desc}:"
+ if bad_methods.length >= 1 then
+ print " Affected method(s):"
+ for method in bad_methods do
+ print " -{method.name} has {method.msignature.mparameters.length} parameters"
+ end
+ end
+ end
+end
+
+class FeatureEnvy
+ super BadConception
+ var bad_methods = new Array[MMethodDef]
+
+ redef fun name do return "FEM"
+
+ redef fun desc do return "Feature envy"
+
+ redef fun collect(mclassdef, model_builder): Bool do
+ var mmethoddefs = call_analyze_methods(mclassdef,model_builder)
+ for mmethoddef in mmethoddefs do
+ if mmethoddef.total_extern_call <= mmethoddef.total_self_call then continue
+ bad_methods.add(mmethoddef)
+ end
+ return bad_methods.not_empty
+ end
+
+ redef fun print_result do
+ print "{desc}:"
+ if bad_methods.length >= 1 then
+ print " Affected method(s):"
+ for method in bad_methods do
+ print " -{method.name} {method.total_self_call}/{method.total_call}"
+ end
+ end
+ end
+end
+
+class LongMethod
+ super BadConception
+ var bad_methods = new Array[MMethodDef]
+
+ redef fun name do return "LONGMETH"
+
+ redef fun desc do return "Long method"
+
+ redef fun collect(mclassdef, model_builder): Bool do
+ var mmethoddefs = call_analyze_methods(mclassdef,model_builder)
+ for mmethoddef in mmethoddefs do
+ if mmethoddef.line_number <= phase.average_number_of_lines.to_i then continue
+ bad_methods.add(mmethoddef)
+ end
+ return bad_methods.not_empty
+ end
+
+ redef fun print_result do
+ print "{desc}: Average {phase.average_number_of_lines.to_i} lines"
+ if bad_methods.length >= 1 then
+ print " Affected method(s):"
+ for method in bad_methods do
+ print " -{method.name} has {method.line_number} lines"
+ end
+ end
+ end
+end
+
+redef class ModelView
+ fun get_avg_parameter: Float do
+ var counter = new Counter[MMethodDef]
+ for mclassdef in mclassdefs do
+ for method in mclassdef.collect_intro_and_redef_mpropdefs(self) do
+ # check if the property is a method definition
+ if not method isa MMethodDef then continue
+ #Check if method has a signature
+ if method.msignature == null then continue
+ if method.msignature.mparameters.length == 0 then continue
+ counter[method] = method.msignature.mparameters.length
+ end
+ end
+ return counter.avg + counter.std_dev
+ end
+
+ fun get_avg_attribut: Float do
+ var counter = new Counter[MClassDef]
+ for mclassdef in mclassdefs do
+ var number_attributs = mclassdef.collect_intro_and_redef_mattributes(self).length
+ if number_attributs != 0 then counter[mclassdef] = number_attributs
+ end
+ return counter.avg + counter.std_dev
+ end
+
+ fun get_avg_method: Float do
+ var counter = new Counter[MClassDef]
+ for mclassdef in mclassdefs do
+ var number_methodes = mclassdef.collect_intro_and_redef_methods(self).length
+ if number_methodes != 0 then counter[mclassdef] = number_methodes
+ end
+ return counter.avg + counter.std_dev
+ end
+
+ fun get_avg_linenumber(model_builder: ModelBuilder): Float do
+ var methods_analyse_metrics = new Counter[MClassDef]
+ for mclassdef in mclassdefs do
+ var result = 0
+ var count = 0
+ for mmethoddef in call_analyze_methods(mclassdef,model_builder) do
+ result += mmethoddef.line_number
+ if mmethoddef.line_number == 0 then continue
+ count += 1
+ end
+ if not mclassdef.collect_local_mproperties(self).length != 0 then continue
+ if count == 0 then continue
+ methods_analyse_metrics[mclassdef] = (result/count).to_i
+ end
+ return methods_analyse_metrics.avg + methods_analyse_metrics.std_dev
+ end
+end
+
+class BadConceptionComparator
+ super Comparator
+ redef type COMPARED: BadConceptionFinder
+ redef fun compare(a,b) do return a.array_badconception.length <=> b.array_badconception.length
+end
--- /dev/null
+# 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.
+# This module redef Mclassdef to add new collect methods.
+
+module mclassdef_collect
+
+# We usualy need specific phases
+# NOTE: `frontend` is sufficent in most case (it is often too much)
+import frontend
+import model_views
+import model_collect
+
+redef class MClassDef
+ # Collect all mproperties introduced in 'self' with `visibility >= min_visibility`.
+ fun collect_intro_mproperties(view: ModelView): Set[MProperty] do
+ var set = new HashSet[MProperty]
+ for mprop in self.intro_mproperties do
+ if not view.accept_mentity(mprop) then continue
+ set.add(mprop)
+ end
+ return set
+ end
+
+ # Collect mmethods introduced in 'self' with `visibility >= min_visibility`.
+ fun collect_intro_mmethods(view: ModelView): Set[MMethod] do
+ var res = new HashSet[MMethod]
+ for mproperty in collect_intro_mproperties(view) do
+ if not view.accept_mentity(mproperty) then continue
+ if mproperty isa MMethod then res.add(mproperty)
+ end
+ return res
+ end
+
+ # Collect mmethods redefined in 'self' with `visibility >= min_visibility`.
+ fun collect_redef_mmethods(view: ModelView): Set[MMethod] do
+ var res = new HashSet[MMethod]
+ for mproperty in collect_redef_mproperties(view) do
+ if not view.accept_mentity(mproperty) then continue
+ if mproperty isa MMethod then res.add(mproperty)
+ end
+ return res
+ end
+
+ # Collect mattributes redefined in 'self' with `visibility >= min_visibility`.
+ fun collect_redef_mattributes(view: ModelView): Set[MAttribute] do
+ var res = new HashSet[MAttribute]
+ for mproperty in collect_redef_mproperties(view) do
+ if not view.accept_mentity(mproperty) then continue
+ if mproperty isa MAttribute then res.add(mproperty)
+ end
+ return res
+ end
+
+ # Collect mattributes introduced in 'self' with `visibility >= min_visibility`.
+ fun collect_intro_mattributes(view: ModelView): Set[MAttribute] do
+ var res = new HashSet[MAttribute]
+ for mproperty in collect_intro_mproperties(view) do
+ if not view.accept_mentity(mproperty) then continue
+ if mproperty isa MAttribute then res.add(mproperty)
+ end
+ return res
+ end
+
+ # Collect all mproperties redefined in 'self' with `visibility >= min_visibility`.
+ fun collect_redef_mproperties(view: ModelView): Set[MProperty] do
+ var set = new HashSet[MProperty]
+ for mpropdef in self.mpropdefs do
+ if not view.accept_mentity(mpropdef) then continue
+ if mpropdef.mproperty.intro_mclassdef.mclass == self then continue
+ set.add(mpropdef.mproperty)
+ end
+ return set
+ end
+
+ # Collect mmethods inherited by 'self' if accepted by `view`.
+ fun collect_inherited_mmethods(view: ModelView): Set[MMethod] do
+ var res = new HashSet[MMethod]
+ for mproperty in collect_inherited_mproperties(view) do
+ if not view.accept_mentity(mproperty) then continue
+ if mproperty isa MMethod then res.add(mproperty)
+ end
+ return res
+ end
+
+ # Collect mproperties introduced and redefined in 'self' with `visibility >= min_visibility`.
+ fun collect_local_mproperties(view: ModelView): Set[MProperty] do
+ var set = new HashSet[MProperty]
+ set.add_all collect_intro_mproperties(view)
+ set.add_all collect_redef_mproperties(view)
+ return set
+ end
+
+ # Collect all mproperties inehrited by 'self' with `visibility >= min_visibility`.
+ fun collect_inherited_mproperties(view: ModelView): Set[MProperty] do
+ var set = new HashSet[MProperty]
+ for parent in collect_parents(view) do
+ set.add_all(parent.collect_intro_mproperties(view))
+ set.add_all(parent.collect_inherited_mproperties(view))
+ end
+ return set
+ end
+
+ # Collect mattributes inherited by 'self' with `visibility >= min_visibility`.
+ fun collect_inherited_mattributes(view: ModelView): Set[MAttribute] do
+ var res = new HashSet[MAttribute]
+ for mproperty in collect_inherited_mproperties(view) do
+ if not view.accept_mentity(mproperty) then continue
+ if mproperty isa MAttribute then res.add(mproperty)
+ end
+ return res
+ end
+
+ fun collect_all_methods(view: ModelView): Set[MMethod] do
+ var set = new HashSet[MMethod]
+ set.add_all collect_intro_mmethods(view)
+ set.add_all collect_redef_mmethods(view)
+ set.add_all collect_inherited_mmethods(view)
+ return set
+ end
+
+ fun collect_all_mattributes(view: ModelView): Set[MAttribute] do
+ var set = new HashSet[MAttribute]
+ set.add_all collect_redef_mattributes(view)
+ set.add_all collect_intro_mattributes(view)
+ set.add_all collect_inherited_mattributes(view)
+ return set
+ end
+
+ fun collect_intro_and_redef_methods(view: ModelView): Set[MMethod] do
+ var set = new HashSet[MMethod]
+ set.add_all collect_intro_mmethods(view)
+ set.add_all collect_redef_mmethods(view)
+ return set
+ end
+
+ fun collect_intro_and_redef_mattributes(view: ModelView): Set[MAttribute] do
+ var set = new HashSet[MAttribute]
+ set.add_all collect_redef_mattributes(view)
+ set.add_all collect_intro_mattributes(view)
+ return set
+ end
+
+ fun collect_intro_and_redef_mproperties(view: ModelView): Set[MProperty] do
+ var set = new HashSet[MProperty]
+ set.add_all collect_redef_mproperties(view)
+ set.add_all collect_intro_mproperties(view)
+ return set
+ end
+
+ fun collect_intro_and_redef_mpropdefs(view: ModelView): Set[MPropDef] do
+ var set = new HashSet[MPropDef]
+ set.add_all collect_intro_mpropdefs(view)
+ set.add_all collect_redef_mpropdefs(view)
+ return set
+ end
+end
--- /dev/null
+# 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.
+# This module call visitor for get number of line, total attributs call and total of self attributes call
+
+module method_analyze_metrics
+
+# We usualy need specific phases
+# NOTE: `frontend` is sufficent in most case (it is often too much)
+import metrics_base
+import mclasses_metrics
+import semantize
+import mclassdef_collect
+
+
+fun call_analyze_methods(mclassdef: MClassDef, model_builder: ModelBuilder): Array[MMethodDef] do
+ var mmethoddefs = new Array[MMethodDef]
+ for m_prop in mclassdef.collect_intro_and_redef_mpropdefs(model_builder.model.private_view) do
+ var n_prop = model_builder.mpropdef2node(m_prop)
+ #Check if the property is a method definition
+ if n_prop isa AMethPropdef and m_prop isa MMethodDef then
+ if n_prop.n_methid isa AIdMethid then
+ #Call visitor to analyse the method
+ var visitor = new MethodAnalyzeMetrics(n_prop)
+ visitor.enter_visit(n_prop)
+ mmethoddefs.add(set_analyse_result_methoddef(m_prop,visitor))
+ end
+ end
+ end
+ return mmethoddefs
+end
+
+fun set_analyse_result_methoddef(mmethoddef: MMethodDef, visitor: MethodAnalyzeMetrics): MMethodDef do
+ mmethoddef.total_call = visitor.total_call
+ mmethoddef.line_number = visitor.line_number.length
+ mmethoddef.total_self_call = visitor.total_self_call
+ mmethoddef.total_extern_call = visitor.total_call - visitor.total_self_call
+ return mmethoddef
+end
+
+public class MethodAnalyzeMetrics
+ super Visitor
+ var ameth_prop_def: AMethPropdef
+ var total_call = 0
+ var line_number = new Counter[nullable Int]
+ var total_self_call = 0
+
+ redef fun visit(n) do
+ n.visit_all(self)
+ if n isa AExpr then
+ if not n isa ABlockExpr then
+ if n.first_location != null then
+ line_number.inc(n.first_location.line_start)
+ end
+ end
+ end
+
+ if n isa ASendExpr then
+ var callsite = n.callsite
+ if callsite != null then
+ self.total_call += 1
+ if callsite.recv_is_self == true then self.total_self_call += 1
+ end
+ end
+ end
+end
+
+redef class MMethodDef
+ var total_call = 0
+ var line_number = 0
+ var total_self_call = 0
+ var total_extern_call = 0
+end
#
# Each classdef is associated with its super-classdefs in regard to
# its module of definition.
+ #
+ # ~~~
+ # var m = new ModelDiamond
+ # assert m.mclassdef_hierarchy.has_edge(m.mclassdef_b, m.mclassdef_a)
+ # assert not m.mclassdef_hierarchy.has_edge(m.mclassdef_a, m.mclassdef_b)
+ # assert not m.mclassdef_hierarchy.has_edge(m.mclassdef_b, m.mclassdef_c)
+ # ~~~
var mclassdef_hierarchy = new POSet[MClassDef]
# Class-type hierarchy restricted to the introduction.
# (instead of an empty array)
#
# Visibility or modules are not considered
+ #
+ # ~~~
+ # var m = new ModelStandalone
+ # assert m.get_mclasses_by_name("Object") == [m.mclass_o]
+ # assert m.get_mclasses_by_name("Fail") == null
+ # ~~~
fun get_mclasses_by_name(name: String): nullable Array[MClass]
do
return mclasses_by_name.get_or_null(name)
fun enum_kind: MClassKind do return once new MClassKind("enum", false)
# The class kind `extern`
fun extern_kind: MClassKind do return once new MClassKind("extern class", false)
+
+# A standalone pre-constructed model used to test various model-related methods.
+#
+# When instantiated, a standalone model is already filled with entities that are exposed as attributes.
+class ModelStandalone
+ super Model
+
+ redef var location = new Location.opaque_file("ModelStandalone")
+
+ # The first module
+ var mmodule0 = new MModule(self, null, "module0", location)
+
+ # The root Object class
+ var mclass_o = new MClass(mmodule0, "Object", location, null, interface_kind, public_visibility)
+
+ # The introduction of `mclass_o`
+ var mclassdef_o = new MClassDef(mmodule0, mclass_o.mclass_type, location)
+end
+
+# A standalone model with the common class diamond-hierarchy ABCD
+class ModelDiamond
+ super ModelStandalone
+
+ # A, a simple subclass of Object
+ var mclass_a = new MClass(mmodule0, "A", location, null, concrete_kind, public_visibility)
+
+ # The introduction of `mclass_a`
+ var mclassdef_a: MClassDef do
+ var res = new MClassDef(mmodule0, mclass_a.mclass_type, location)
+ res.set_supertypes([mclass_o.mclass_type])
+ res.add_in_hierarchy
+ return res
+ end
+
+ # B, a subclass of A (`mclass_a`)
+ var mclass_b = new MClass(mmodule0, "B", location, null, concrete_kind, public_visibility)
+
+ # The introduction of `mclass_b`
+ var mclassdef_b: MClassDef do
+ var res = new MClassDef(mmodule0, mclass_b.mclass_type, location)
+ res.set_supertypes([mclass_a.mclass_type])
+ res.add_in_hierarchy
+ return res
+ end
+
+ # C, another subclass of A (`mclass_a`)
+ var mclass_c = new MClass(mmodule0, "C", location, null, concrete_kind, public_visibility)
+
+ # The introduction of `mclass_c`
+ var mclassdef_c: MClassDef do
+ var res = new MClassDef(mmodule0, mclass_c.mclass_type, location)
+ res.set_supertypes([mclass_a.mclass_type])
+ res.add_in_hierarchy
+ return res
+ end
+
+ # D, a multiple subclass of B (`mclass_b`) and C (`mclass_c`)
+ var mclass_d = new MClass(mmodule0, "D", location, null, concrete_kind, public_visibility)
+
+ # The introduction of `mclass_d`
+ var mclassdef_d: MClassDef do
+ var res = new MClassDef(mmodule0, mclass_d.mclass_type, location)
+ res.set_supertypes([mclass_b.mclass_type, mclass_c.mclass_type])
+ res.add_in_hierarchy
+ return res
+ end
+end
private fun build_a_mclassdef(nmodule: AModule, nclassdef: AClassdef)
do
var mmodule = nmodule.mmodule.as(not null)
- var objectclass = try_get_mclass_by_name(nmodule, mmodule, "Object")
var mclass = nclassdef.mclass
if mclass == null then return # Skip error
return
end
+ var bound_mtype = build_a_bound_mtype(nmodule, nclassdef)
+ if bound_mtype == null then return
+ var mclassdef = new MClassDef(mmodule, bound_mtype, nclassdef.location)
+ nclassdef.mclassdef = mclassdef
+ self.mclassdef2nclassdef[mclassdef] = nclassdef
+
+ if nclassdef isa AStdClassdef then
+ var ndoc = nclassdef.n_doc
+ if ndoc != null then
+ var mdoc = ndoc.to_mdoc
+ mclassdef.mdoc = mdoc
+ mdoc.original_mentity = mclassdef
+ else if mclassdef.is_intro and mclass.visibility >= public_visibility then
+ advice(nclassdef, "missing-doc", "Documentation warning: Undocumented public class `{mclass}`")
+ end
+ end
+
+ if mclassdef.is_intro then
+ self.toolcontext.info("{mclassdef} introduces new {mclass.kind} {mclass.full_name}", 3)
+ else
+ self.toolcontext.info("{mclassdef} refines {mclass.kind} {mclass.full_name}", 3)
+ end
+ end
+
+ # Determine the type parameter bounds for `nclassdef`.
+ #
+ # In case of error, return `null`.
+ #
+ # REQUIRE: `nmodule.mmodule != null`
+ # REQUIRE: `nclassdef.mclass != null`
+ private fun build_a_bound_mtype(nmodule: AModule, nclassdef: AClassdef): nullable MClassType
+ do
+ var mmodule = nmodule.mmodule.as(not null)
+ var mclass = nclassdef.mclass.as(not null)
+
var bounds = new Array[MType]
if nclassdef isa AStdClassdef and mclass.arity > 0 then
+ var objectclass = try_get_mclass_by_name(nmodule, mmodule, "Object")
+
# Revolve bound for formal parameters
for i in [0..mclass.arity[ do
if nclassdef.n_formaldefs.is_empty then
var nfdt = nfd.n_type
if nfdt != null then
var bound = resolve_mtype3_unchecked(mmodule, null, null, nfdt, false)
- if bound == null then return # Forward error
+ if bound == null then return null # Forward error
if bound.need_anchor then
# No F-bounds!
error(nfd, "Error: formal parameter type `{pname}` bounded with a formal parameter type.")
else if mclass.mclassdefs.is_empty then
if objectclass == null then
error(nfd, "Error: formal parameter type `{pname}` unbounded but no `Object` class exists.")
- return
+ return null
end
# No bound, then implicitely bound by nullable Object
var bound = objectclass.mclass_type.as_nullable
end
end
- var bound_mtype = mclass.get_mtype(bounds)
- var mclassdef = new MClassDef(mmodule, bound_mtype, nclassdef.location)
- nclassdef.mclassdef = mclassdef
- self.mclassdef2nclassdef[mclassdef] = nclassdef
-
- if nclassdef isa AStdClassdef then
- var ndoc = nclassdef.n_doc
- if ndoc != null then
- var mdoc = ndoc.to_mdoc
- mclassdef.mdoc = mdoc
- mdoc.original_mentity = mclassdef
- else if mclassdef.is_intro and mclass.visibility >= public_visibility then
- advice(nclassdef, "missing-doc", "Documentation warning: Undocumented public class `{mclass}`")
- end
- end
-
- if mclassdef.is_intro then
- self.toolcontext.info("{mclassdef} introduces new {mclass.kind} {mclass.full_name}", 3)
- else
- self.toolcontext.info("{mclassdef} refines {mclass.kind} {mclass.full_name}", 3)
- end
+ return mclass.get_mtype(bounds)
end
# Visit the AST and set the super-types of the `MClassDef` objects
- private fun collect_a_mclassdef_inheritance(nmodule: AModule, nclassdef: AClassdef)
+ private fun build_a_mclassdef_inheritance(nmodule: AModule, nclassdef: AClassdef)
do
var mmodule = nmodule.mmodule
if mmodule == null then return
- var objectclass = try_get_mclass_by_name(nmodule, mmodule, "Object")
- var pointerclass = try_get_mclass_by_name(nmodule, mmodule, "Pointer")
var mclass = nclassdef.mclass
if mclass == null then return
var mclassdef = nclassdef.mclassdef
if mclassdef == null then return
+ var supertypes = collect_supertypes(nmodule, nclassdef, mclassdef.is_intro)
+ mclassdef.set_supertypes(supertypes)
+ if not supertypes.is_empty then self.toolcontext.info("{mclassdef} new super-types: {supertypes.join(", ")}", 3)
+ end
+
+ # List the supertypes specified or implied by `nclassdef`.
+ #
+ # REQUIRE: `nmodule.mmodule != null`
+ # REQUIRE: `nclassdef.mclass != null`
+ private fun collect_supertypes(nmodule: AModule, nclassdef: AClassdef,
+ is_intro: Bool): Array[MClassType]
+ do
+ var mmodule = nmodule.mmodule.as(not null)
+ var mclass = nclassdef.mclass.as(not null)
+ var name = mclass.name
+ var kind = mclass.kind
+
+ var objectclass = try_get_mclass_by_name(nmodule, mmodule, "Object")
+ var pointerclass = try_get_mclass_by_name(nmodule, mmodule, "Pointer")
+
# Do we need to specify Object as a super class?
var specobject = true
for nsc in nclassdef.n_superclasses do
specobject = false
var ntype = nsc.n_type
- var mtype = resolve_mtype_unchecked(mclassdef, ntype, false)
+ var mtype = resolve_mtype3_unchecked(mmodule, mclass, null,
+ ntype, false)
if mtype == null then continue # Skip because of error
if not mtype isa MClassType then
- error(ntype, "Error: supertypes cannot be a formal type.")
- return
+ error(ntype, "Error: a supertype cannot be a formal type.")
+ continue
end
- if not mclass.kind.can_specialize(mtype.mclass.kind) then
- error(ntype, "Error: {mclass.kind} `{mclass}` cannot specialize {mtype.mclass.kind} `{mtype.mclass}`.")
+ var superclass = mtype.mclass
+ var super_kind = superclass.kind
+ if not kind.can_specialize(super_kind) then
+ error(ntype, "Error: {kind} `{mclass}` cannot specialize {super_kind} `{superclass}`.")
end
supertypes.add mtype
#print "new super : {mclass} < {mtype}"
- if mtype.mclass.kind == extern_kind then specpointer = false
+ if super_kind == extern_kind then specpointer = false
end
end
- if mclassdef.is_intro and objectclass != null then
- if mclass.kind == extern_kind and mclass.name != "Pointer" then
+ if is_intro and objectclass != null then
+ if kind == extern_kind and name != "Pointer" then
# it is an extern class, but not a Pointer
if pointerclass == null then
error(nclassdef, "Error: `Pointer` must be defined first.")
- return
+ return supertypes
end
if specpointer then supertypes.add pointerclass.mclass_type
else if specobject then
- if mclass.name != "Object" then
+ if name != "Object" then
# it is a standard class without super class (but is not Object)
supertypes.add objectclass.mclass_type
- else if mclass.kind != interface_kind then
+ else if kind != interface_kind then
error(nclassdef, "Error: `Object` must be an {interface_kind}.")
- return
end
end
end
- mclassdef.set_supertypes(supertypes)
- if not supertypes.is_empty then self.toolcontext.info("{mclassdef} new super-types: {supertypes.join(", ")}", 3)
+ return supertypes
end
# Check the validity of the specialization heirarchy
# Create inheritance on all classdefs
for nclassdef in nmodule.n_classdefs do
- self.collect_a_mclassdef_inheritance(nmodule, nclassdef)
+ self.build_a_mclassdef_inheritance(nmodule, nclassdef)
end
# Create the mclassdef hierarchy
for nsc in nclassdef.n_superclasses do
var ntype = nsc.n_type
var mtype = ntype.mtype
- if mtype == null then continue
- assert mtype isa MClassType
+
+ # If the supertype is `null` or don’t refer to a class, we
+ # already raised an error.
+ if not mtype isa MClassType then continue
+
var sc = mtype.mclass
if not parents.has(sc) or sc == objectclass then
# Skip the warning on generated code
do
var n_kwinit = n_kwinit
var n_kwnew = n_kwnew
- var is_init = n_kwinit != null or n_kwnew != null
+ var is_new = n_kwnew != null
+ var is_init = n_kwinit != null or is_new
var name: String
var amethodid = self.n_methid
var name_node: ANode
if amethodid == null then
- if not is_init then
- name = "main"
- name_node = self
- else if n_kwinit != null then
+ if n_kwinit != null then
name = "init"
name_node = n_kwinit
else if n_kwnew != null then
name = "new"
name_node = n_kwnew
else
- abort
+ name = "main"
+ name_node = self
end
else if amethodid isa AIdMethid then
name = amethodid.n_id.text
mprop.is_root_init = true
end
mprop.is_init = is_init
- mprop.is_new = n_kwnew != null
- if mprop.is_new then mclassdef.mclass.has_new_factory = true
+ mprop.is_new = is_new
+ if is_new then mclassdef.mclass.has_new_factory = true
if name == "sys" then mprop.is_toplevel = true # special case for sys allowed in `new` factories
if not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, mprop) then
mprop.is_broken = true
do
var mpropdef = self.mpropdef
if mpropdef == null then return # Error thus skiped
+ var mproperty = mpropdef.mproperty
var mclassdef = mpropdef.mclassdef
var mmodule = mclassdef.mmodule
var nsig = self.n_signature
- if mpropdef.mproperty.is_root_init and not mclassdef.is_intro then
+ if mproperty.is_root_init and not mclassdef.is_intro then
var root_init = mclassdef.mclass.root_init
if root_init != null then
# Inherit the initializers by refinement
# FIXME: do not inherit from the intro, but from the most specific
var msignature: nullable MSignature = null
if not mpropdef.is_intro then
- msignature = mpropdef.mproperty.intro.msignature
+ msignature = mproperty.intro.msignature
if msignature == null then return # Skip error
# The local signature is adapted to use the local formal types, if any.
if param_names.length != msignature.arity then
var node: ANode
if nsig != null then node = nsig else node = self
- modelbuilder.error(node, "Redef Error: expected {msignature.arity} parameter(s) for `{mpropdef.mproperty.name}{msignature}`; got {param_names.length}. See introduction at `{mpropdef.mproperty.full_name}`.")
+ modelbuilder.error(node, "Redef Error: expected {msignature.arity} parameter(s) for `{mproperty.name}{msignature}`; got {param_names.length}. See introduction at `{mproperty.full_name}`.")
return
end
- else if mpropdef.mproperty.is_init and not mpropdef.mproperty.is_new then
+ else if mproperty.is_init and not mproperty.is_new then
# FIXME UGLY: inherit signature from a super-constructor
for msupertype in mclassdef.supertypes do
msupertype = msupertype.anchor_to(mmodule, mclassdef.bound_mtype)
- var candidate = modelbuilder.try_get_mproperty_by_name2(self, mmodule, msupertype, mpropdef.mproperty.name)
+ var candidate = modelbuilder.try_get_mproperty_by_name2(self, mmodule, msupertype, mproperty.name)
if candidate != null then
if msignature == null then
msignature = candidate.intro.as(MMethodDef).msignature
end
# In `new`-factories, the return type is by default the classtype.
- if ret_type == null and mpropdef.mproperty.is_new then ret_type = mclassdef.mclass.mclass_type
+ if ret_type == null and mproperty.is_new then ret_type = mclassdef.mclass.mclass_type
# Special checks for operator methods
if not accept_special_last_parameter and mparameters.not_empty and mparameters.last.is_vararg then
- modelbuilder.error(self.n_signature.n_params.last, "Error: illegal variadic parameter `{mparameters.last}` for `{mpropdef.mproperty.name}`.")
+ modelbuilder.error(self.n_signature.n_params.last, "Error: illegal variadic parameter `{mparameters.last}` for `{mproperty.name}`.")
end
if ret_type == null and return_is_mandatory then
- modelbuilder.error(self.n_methid, "Error: mandatory return type for `{mpropdef.mproperty.name}`.")
+ modelbuilder.error(self.n_methid, "Error: mandatory return type for `{mproperty.name}`.")
end
msignature = new MSignature(mparameters, ret_type)
--- /dev/null
+# 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.
+
+import metrics_base
+import mclasses_metrics
+import semantize
+
+import codesmells_metrics
+
+# Create a tool context to handle options and paths
+var toolcontext = new ToolContext
+toolcontext.tooldescription = "Usage: nitsmells [OPTION]... <file.nit>...\n Computes code smells on Nit programs."
+# We do not add other options, so process them now!
+toolcontext.process_options(args)
+# Get arguments
+var arguments = toolcontext.option_context.rest
+# We need a model to collect stufs
+var model = new Model
+# An a model builder to parse files
+var modelbuilder = new ModelBuilder(model, toolcontext)
+# Here we load an process all modules passed on the command line
+var mmodules = modelbuilder.parse_full(arguments)
+modelbuilder.run_phases
+print "*** CODE SMELLS METRICS ***"
+toolcontext.run_global_phases(mmodules)
end
return new Namespace.from([mmodule.full_name, "$::", mclass.intro_mmodule.to_ns_ref: nullable NSEntity])
end
+
+ redef fun web_url do return "{mclass.web_url}/lin#{full_name}"
end
redef class MProperty
end
return res
end
+
+ redef fun web_url do return "{mproperty.web_url}/lin#{full_name}"
end
redef class MClassType
--- /dev/null
+# 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.
+
+# A test program with a fake model to check model tools.
+module featureenvy
+
+import platform
+
+class Starter
+ var attribute = 0
+ var attribute1 = 0
+ var attribute2 = 0
+ fun start do
+ self.attribute1 = 10
+ self.attribute = 2
+ end
+
+ fun ended do end
+end
+
+class FeatureEnvy
+ var testVariable = 0
+
+ fun feature_envy_method do
+ var starter = new Starter
+ testVariable = starter.attribute
+ if starter.attribute == self.testVariable then
+ starter.attribute = 10
+ end
+ end
+end
--- /dev/null
+# 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.
+
+# A test program with a fake model to check model tools.
+module largeclass
+
+import platform
+
+class LargeClass
+ var attribute = 0
+ var attribute1 = 0
+ var attribute2 = 0
+ var attribute3 = 0
+ var attribute4 = 0
+ var attribute5 = 0
+ var attribut6 = 0
+ var attribute7 = 0
+ var attribute8 = 0
+ var attribute9 = 0
+ var attribute10 = 0
+ var attribute11 = 0
+ var attribute12 = 0
+ var attribute13 = 0
+ var attribute14 = 0
+ var attribute15 = 0
+ var attribute16 = 0
+ var attribute17 = 0
+
+ fun start do
+ self.attribute16 = 10
+ end
+
+ fun ended do end
+ fun replay do end
+ fun restart do end
+ fun start1 do end
+ fun ended1 do end
+ fun replay1 do end
+ fun restart1 do end
+ fun start2 do end
+ fun ended2 do end
+ fun replay2 do end
+ fun restart2 do end
+end
+
+class NoLargeclass
+ var testVariable = 0
+
+ fun test do end
+end
\ No newline at end of file
--- /dev/null
+# 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.
+
+# A test program with a fake model to check model tools.
+module longmethod
+
+import platform
+
+class Starter
+ var attribute = 0
+ var attribute1 = 0
+ var attribute2 = 0
+ fun start do
+ self.attribute1 = 10
+ end
+
+ fun ended do end
+end
+
+class LongMethodClass
+ var test_variable = 0
+
+ fun long_method do
+ var starter = new Starter
+ test_variable = 3
+ end
+end
\ No newline at end of file
--- /dev/null
+# 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.
+
+# A test program with a fake model to check model tools.
+module longparameterlist
+
+import platform
+
+class Starter
+ fun no_para do end
+
+ fun no_para2() do end
+end
+
+class Test
+ fun short_list_parameter(numbers : Int, para1 : Bool, para2 : Float, para3 : Int) do
+ var starter = new Starter
+ end
+
+ fun long_list_parameter(numbers : Int, para1 : Bool, para2 : Float, para3 : Int, para4 : Starter) do
+ var starter = new Starter
+ end
+end
--- /dev/null
+# 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.
+
+# Declares base types allowed on the platform.
+module platform
+
+import end
+
+# Root of everything.
+interface Object
+ # Used for comparisons.
+ type OTHER: nullable Object
+
+ # Is `other` equqls to `self`?
+ fun ==(other: OTHER): Bool is intern
+
+ # Is `other` different from `self`?
+ fun !=(other: OTHER): Bool do return not self == other
+end
+
+# Some services about Integers.
+class Int
+ fun -: Int is intern
+ fun +(i: Int): Int is intern
+ fun -(i: Int): Int is intern
+ fun *(i: Int): Int is intern
+ fun /(i: Int): Int is intern
+ fun >(i: Int): Bool is intern
+ fun to_f: Float is intern
+end
+
+# Some services about Floats.
+class Float
+ fun +(f: Float): Float is intern
+ fun -(f: Float): Float is intern
+ fun *(f: Float): Float is intern
+ fun /(f: Float): Float is intern
+ fun >(f: Float): Bool is intern
+end
+
+# Booleans, `true` or `false`.
+class Bool end
+
+# Strings (there is no chars...).
+class String end
+
+# List of things.
+class List[E] end
--- /dev/null
+# 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.
+
+# Test of formal types as supertypes.
+
+import core::kernel
+
+class Foo[E]
+ super E
+end
--- /dev/null
+--no-colors test_prog/
+--no-colors TestNitsmells/FeatureEnvy/
+--no-colors TestNitsmells/LargeClass/
+--no-colors TestNitsmells/LongMethod/
+--no-colors TestNitsmells/LongParameterList/
\ No newline at end of file
--- /dev/null
+digraph "G" {
+subgraph "cluster_0" {
+label="process #1";
+style="filled";
+color="lightgrey";
+node[style="filled",color="white",];
+"a0" ;
+"a1" ;
+"a2" ;
+"a3" ;
+"a0" -> "a1" ;
+"a1" -> "a2" ;
+"a2" -> "a3" ;
+};
+subgraph "cluster_1" {
+label="process #2";
+color="blue";
+node[style="filled",];
+"b0" ;
+"b1" ;
+"b2" ;
+"b3" ;
+"b0" -> "b1" ;
+"b1" -> "b2" ;
+"b2" -> "b3" ;
+};
+"start" [shape="Mdiamond",];
+"end" [shape="Msquare",];
+"start" -> "a0" ;
+"start" -> "b0" ;
+"a1" -> "b3" ;
+"b2" -> "a3" ;
+"a3" -> "a0" ;
+"a3" -> "end" ;
+"b3" -> "end" ;
+}
--- /dev/null
+error_formal_super.nit:20,8: Error: a supertype cannot be a formal type.
--- /dev/null
+digraph "G" {
+"hello" ;
+"world" ;
+"hello" -> "world" ;
+}
--- /dev/null
+Usage: nitsmells [OPTION]... <file.nit>...
+ Computes code smells on Nit programs.
+Use --help for help
--- /dev/null
+*** CODE SMELLS METRICS ***
+--- Code Smells Metrics ---
+-----------
+test_prog$Character
+Large class: 6 attributes and 18 methods (5.414A 7.161M Average)
+Feature envy:
+ Affected method(s):
+ -total_strengh 4/9
+ -total_endurance 4/9
+ -total_intelligence 4/9
+Long method: Average 1 lines
+ Affected method(s):
+ -total_strengh has 2 lines
+ -total_endurance has 2 lines
+ -total_intelligence has 2 lines
+-----------
+test_prog::combat$Dwarf
+Feature envy:
+ Affected method(s):
+ -dps 1/3
--- /dev/null
+*** CODE SMELLS METRICS ***
+--- Code Smells Metrics ---
+-----------
+TestNitsmells$FeatureEnvy
+Feature envy:
+ Affected method(s):
+ -feature_envy_method 2/6
--- /dev/null
+*** CODE SMELLS METRICS ***
+--- Code Smells Metrics ---
+-----------
+TestNitsmells$LargeClass
+Large class: 18 attributes and 48 methods (17.515A 30.464M Average)
--- /dev/null
+*** CODE SMELLS METRICS ***
+--- Code Smells Metrics ---
+-----------
+TestNitsmells$LongMethodClass
+Long method: Average 1 lines
+ Affected method(s):
+ -long_method has 2 lines
--- /dev/null
+graph "G" {
+subgraph "clusterA" {
+"a" -- "b" ;
+subgraph "clusterB" {
+"c" -- "d" ;
+};
+};
+subgraph "clusterC" {
+"e" -- "g" ;
+};
+"e" -- "d" ;
+"f" -- "g" ;
+}
import neo4j
+# key used to loosely assume unicity and prevent conflicting db accesses
var key = "NIT_TESTING_ID".environ.to_i
var srv = new Neo4jServer
var client = new Neo4jClient("http://localhost:7474")
assert client.is_ok
+# Clear the previous objects, if any
+client.cypher(new CypherQuery.from_string("MATCH (n) WHERE n.key = {key} OPTIONAL MATCH n-[r]-() DELETE r, n"))
+
var andres = new NeoNode
andres.labels.add_all(["PERSON", "MALE"])
andres["name"] = "Andres"
nand("n.key = {key}").
nreturn("n, r, m")
var res7 = client.cypher(query)
-assert not res7.as(JsonObject)["data"].as(JsonArray).is_empty
+assert res7.as(JsonObject)["data"].as(JsonArray).length == 1
var srv = new Neo4jServer
srv.start_quiet
+# key used to loosely assume unicity and prevent conflicting db accesses
var key = "NIT_TESTING_ID".environ.to_i
var andres = new NeoNode
var client = new Neo4jClient("http://localhost:7474")
assert client.is_ok
+# Clear the previous objects, if any
+client.cypher(new CypherQuery.from_string("MATCH (n) WHERE n.key = {key} OPTIONAL MATCH n-[r]-() DELETE r, n"))
+
print "# Save batch\n"
var batch = new NeoBatch(client)
fi
# Detect a working time command
-if env time --quiet -f%U true 2>/dev/null; then
- TIME="env time --quiet -f%U"
-elif env time -f%U true 2>/dev/null; then
- TIME="env time -f%U"
-elif env gtime -f%U true 2>/dev/null; then
- TIME="env gtime -f%U"
+if command time --quiet -f%e true 2>/dev/null; then
+ TIME="command time --quiet -f%e"
+elif command time -f%e true 2>/dev/null; then
+ TIME="command time -f%e"
+elif command gtime -f%e true 2>/dev/null; then
+ TIME="command gtime -f%e"
else
TIME=
fi