To run the listener:
+~~~raw
./listener <host> <port>
+~~~
The arguments `host` and `port` must correspond to what you entered in your
GitHub hook settings.
To run the webserver:
+~~~raw
./web <host> <port> <root>
+~~~
The arguments `host` and `port` must correspond to what you entered in your
GitHub hook settings.
For example, if NitRPG is installed in `yourdomain.com/nitrpg`:
+~~~raw
./web localhost 3000 "/nitrpg"
+~~~
Leave it empty if NitRPG is installed at the root of the domain:
+~~~raw
./web localhost 3000 ""
+~~~
The webserver can then be accessed at `http://yourdomain.com:3000/nitrpg/`.
--- /dev/null
+[package]
+name=config
+tags=config,options,ini,lib
+maintainer=Alexandre Terrasa <alexandre@moz-code.org>
+license=Apache-2.0
+[upstream]
+browse=https://github.com/nitlang/nit/tree/master/lib/config.nit
+git=https://github.com/nitlang/nit.git
+git.directory=lib/config.nit
+homepage=http://nitlanguage.org
+issues=https://github.com/nitlang/nit/issues
--- /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.
+
+# Configuration options for nit tools and apps
+#
+# This module provides basic services for options handling in your Nit programs.
+#
+# ## Basic configuration holder
+#
+# The `Config` class can be used as a simple option holder and processor:
+#
+# ~~~
+# import config
+#
+# # Create a new config option
+# var opt_my = new OptionString("My option", "--my")
+#
+# # Create the config and add the option
+# var config = new Config
+# config.add_option(opt_my)
+#
+# # Parse the program arguments, usually `args`
+# config.parse_options(["--my", "myOption", "arg1", "arg2"])
+#
+# # Access the options and args
+# assert opt_my.value == "myOption"
+# assert config.args == ["arg1", "arg2"]
+# ~~~
+#
+# ## Custom configuration class
+#
+# Instead of using basic `Config` instances, it is better to define new sublcasses
+# to store options and define custom services.
+#
+# ~~~
+# import config
+#
+# class MyConfig
+# super Config
+#
+# var opt_my = new OptionString("My option", "--my")
+#
+# init do
+# super
+# tool_description = "Usage: MyExample [OPTION]... [ARGS]..."
+# add_option(opt_my)
+# end
+#
+# fun my: String do return opt_my.value or else "Default value"
+# end
+#
+# var config = new MyConfig
+# config.parse_options(["--my", "myOption", "arg1", "arg2"])
+#
+# assert config.my == "myOption"
+# assert config.args == ["arg1", "arg2"]
+# ~~~
+#
+# We define the `my` method to provide an elegant shortcut to `opt_my.value`
+# and define the default value if the option was not set by the user.
+#
+# The `tool_description` attribute is used to set the `usage` header printed when
+# the user request the `help` message.
+#
+# ~~~
+# config.parse_options(["-h"])
+# if config.help then
+# config.usage
+# exit 0
+# end
+# ~~~
+#
+# This will display the tool usage like this:
+#
+# ~~~raw
+# Usage: MyExample [OPTION]... [ARGS]...
+# -h, --help Show this help message
+# --my My option
+# ~~~
+#
+# ## Configuration with `ini` file
+#
+# The `IniConfig` class extends `Config` to add an easy way to link your
+# configuration to an ini file.
+
+# ~~~
+# class MyIniConfig
+# super IniConfig
+#
+# var opt_my = new OptionString("My option", "--my")
+#
+# init do
+# super
+# tool_description = "Usage: MyExample [OPTION]... [ARGS]..."
+# opts.add_option(opt_my)
+# end
+#
+# fun my: String do return opt_my.value or else ini["my"] or else "Default"
+# end
+# ~~~
+#
+# This time, we define the `my` method to return the option value or the ini
+# if no option was passed. Finally, if no ini value can be found, we return the
+# default value.
+#
+# By default, `IniConfig` looks at a `config.ini` file in the execution directory.
+# This can be overrided in multiple ways.
+#
+# First by the app user by setting the `--config` option:
+#
+# ~~~
+# var config = new MyIniConfig
+# config.parse_options(["--config", "my_config.ini"])
+#
+# assert config.config_file == "my_config.ini"
+# ~~~
+#
+# Default config file can also be changed by the library client through the
+# `default_config_file` attribute:
+#
+# ~~~
+# config = new MyIniConfig
+# config.default_config_file = "my_config.ini"
+# config.parse_options(["arg"])
+#
+# assert config.config_file == "my_config.ini"
+# ~~~
+#
+# Or by the library developper in the custom config class:
+#
+# ~~~
+# class MyCustomIniConfig
+# super IniConfig
+#
+# redef var default_config_file = "my_config.ini"
+# end
+#
+# var config = new MyCustomIniConfig
+# config.parse_options(["arg"])
+#
+# assert config.config_file == "my_config.ini"
+# ~~~
+module config
+
+import ini
+import opts
+
+# Basic configuration class
+#
+# ~~~
+# import config
+#
+# class MyConfig
+# super Config
+#
+# var opt_my = new OptionString("My option", "--my")
+#
+# init do
+# super
+# tool_description = "Usage: MyExample [OPTION]... [ARGS]..."
+# opts.add_option(opt_my)
+# end
+#
+# fun my: String do return opt_my.value or else "Default value"
+# end
+#
+# var config = new MyConfig
+# config.parse_options(["--my", "hello", "arg1", "arg2"])
+# assert config.my == "hello"
+# assert config.args == ["arg1", "arg2"]
+# ~~~
+class Config
+
+ # Context used to store and parse options
+ var opts = new OptionContext
+
+ # Help option
+ var opt_help = new OptionBool("Show this help message", "-h", "--help")
+
+ # Redefine this init to add your options
+ init do
+ add_option(opt_help)
+ end
+
+ # Add an option to `self`
+ #
+ # Shortcut to `opts.add_option`.
+ fun add_option(opt: Option...) do opts.add_option(opt...)
+
+ # Initialize `self` options from `args`
+ fun parse_options(args: Collection[String]) do
+ opts.parse(args)
+ end
+
+ # Return the remaining args once options are parsed by `from_args`
+ fun args: Array[String] do return opts.rest
+
+ # Name, usage and synopsis of the tool.
+ # It is mainly used in `usage`.
+ # Should be correctly set by the client before calling `usage`
+ # A multi-line string is recommended.
+ #
+ # eg. `"Usage: tool [OPTION]... [FILE]...\nDo some things."`
+ var tool_description: String = "Usage: [OPTION]... [ARG]..." is writable
+
+ # Was the `--help` option requested?
+ fun help: Bool do return opt_help.value
+
+ # Display `tool_description` and options usage in console
+ fun usage do
+ print tool_description
+ opts.usage
+ end
+end
+
+# Configuration class based on a INI file.
+#
+# ~~~
+# class MyIniConfig
+# super IniConfig
+#
+# var opt_my = new OptionString("My option", "--my")
+#
+# init do
+# super
+# tool_description = "Usage: MyExample [OPTION]... [ARGS]..."
+# opts.add_option(opt_my)
+# end
+#
+# fun my: String do return opt_my.value or else ini["my"] or else "Default"
+# end
+#
+# var config = new MyIniConfig
+# config.default_config_file = "my_config.ini"
+# config.parse_options(args)
+#
+# if config.help then
+# config.usage
+# exit 0
+# end
+#
+# assert config.my == "Default"
+# ~~~
+class IniConfig
+ super Config
+
+ # Config tree used to store config options
+ var ini: ConfigTree is noinit
+
+ # Path to app config file
+ var opt_config = new OptionString("Path to config file", "--config")
+
+ init do
+ super
+ opts.add_option(opt_config)
+ end
+
+ redef fun parse_options(args) do
+ super
+ ini = new ConfigTree(config_file)
+ end
+
+ # Default config file path
+ var default_config_file = "config.ini" is writable
+
+ # Return the config file path from options or the default
+ fun config_file: String do return opt_config.value or else default_config_file
+end
# Decode `self` from percent (or URL) encoding to a clear string
#
- # Replace invalid use of '%' with '?'.
+ # Invalid '%' are not decoded.
#
# assert "aBc09-._~".to_bytes.from_percent_encoding == "aBc09-._~".to_bytes
# assert "%25%28%29%3c%20%3e".to_bytes.from_percent_encoding == "%()< >".to_bytes
# assert ".com%2fpost%3fe%3dasdf%26f%3d123".to_bytes.from_percent_encoding == ".com/post?e=asdf&f=123".to_bytes
# assert "%25%28%29%3C%20%3E".to_bytes.from_percent_encoding == "%()< >".to_bytes
- # assert "incomplete %".to_bytes.from_percent_encoding == "incomplete ?".to_bytes
- # assert "invalid % usage".to_bytes.from_percent_encoding == "invalid ? usage".to_bytes
+ # assert "incomplete %".to_bytes.from_percent_encoding == "incomplete %".to_bytes
+ # assert "invalid % usage".to_bytes.from_percent_encoding == "invalid % usage".to_bytes
# assert "%c3%a9%e3%81%82%e3%81%84%e3%81%86".to_bytes.from_percent_encoding == "éあいう".to_bytes
+ # assert "%1 %A %C3%A9A9".to_bytes.from_percent_encoding == "%1 %A éA9".to_bytes
fun from_percent_encoding: Bytes do
var tmp = new Bytes.with_capacity(length)
var pos = 0
continue
end
if length - pos < 2 then
- tmp.add '?'.ascii
+ tmp.add '%'.ascii
pos += 1
continue
end
var bn = self[pos + 1]
var bnn = self[pos + 2]
if not bn.is_valid_hexdigit or not bnn.is_valid_hexdigit then
- tmp.add '?'.ascii
+ tmp.add '%'.ascii
pos += 1
continue
end
# Decode `self` from percent (or URL) encoding to a clear string
#
- # Replace invalid use of '%' with '?'.
+ # Invalid '%' are not decoded.
#
# assert "aBc09-._~".from_percent_encoding == "aBc09-._~"
# assert "%25%28%29%3c%20%3e".from_percent_encoding == "%()< >"
# assert ".com%2fpost%3fe%3dasdf%26f%3d123".from_percent_encoding == ".com/post?e=asdf&f=123"
# assert "%25%28%29%3C%20%3E".from_percent_encoding == "%()< >"
- # assert "incomplete %".from_percent_encoding == "incomplete ?"
- # assert "invalid % usage".from_percent_encoding == "invalid ? usage"
+ # assert "incomplete %".from_percent_encoding == "incomplete %"
+ # assert "invalid % usage".from_percent_encoding == "invalid % usage"
# assert "%c3%a9%e3%81%82%e3%81%84%e3%81%86".from_percent_encoding == "éあいう"
+ # assert "%1 %A %C3%A9A9".from_percent_encoding == "%1 %A éA9"
fun from_percent_encoding: String
do
var len = byte_length
if c == '%' then
if i + 2 >= length then
# What follows % has been cut off
- buf[l] = '?'.ascii
+ buf[l] = '%'.ascii
else
i += 1
var hex_s = substring(i, 2)
i += 1
else
# What follows a % is not Hex
- buf[l] = '?'.ascii
+ buf[l] = '%'.ascii
i -= 1
end
end
# Changed files count.
var changed_files: Int is writable
+
+ # URL to patch file
+ var patch_url: nullable String is writable
end
# A pull request reference (used for head and base).
private var optmap = new HashMap[String, Option]
# Add one or more options to the context
- fun add_option(opts: Option...) do
- options.add_all(opts)
- end
+ fun add_option(opts: Option...) do options.add_all(opts)
# Display all the options available
fun usage
# import popcorn
# import popcorn::pop_config
#
-# # Parse app options
-# var opts = new AppOptions.from_args(args)
-#
# # Build config from options
-# var config = new AppConfig.from_options(opts)
+# var config = new AppConfig
+# config.parse_options(args)
#
# # Use options
# var app = new App
# super AppConfig
#
# # My secret code I don't want to share in my source repository
-# var secret: String = value_or_default("secret", "my-secret")
-#
-# redef init from_options(options) do
-# super
-# if options isa MyOptions then
-# var secret = options.opt_secret.value
-# if secret != null then self["secret"] = secret
-# end
-# end
-# end
-#
-# class MyOptions
-# super AppOptions
+# fun secret: String do return opt_secret.value or else ini["secret"] or else "my-secret"
#
+# # opt --secret
# var opt_secret = new OptionString("My secret string", "--secret")
#
# redef init do
# end
# end
#
-# var opts = new MyOptions.from_args(args)
-# var config = new MyConfig.from_options(opts)
+# var config = new MyConfig
+# config.parse_options(args)
#
# var app = new App
# app.use("/secret", new SecretHandler(config))
# ~~~
module pop_config
-import ini
-import opts
+import config
# Configuration file for Popcorn apps
#
# import popcorn::pop_config
#
# # Build config from default values
-# var config = new AppConfig("app.ini")
+# var config = new AppConfig
+# config.parse_options(args)
#
# # Change config values
-# config["app.port"] = 3001.to_s
+# config.ini["app.port"] = 3001.to_s
#
# # Use options
# var app = new App
# app.listen(config.app_host, config.app_port)
# ~~~
class AppConfig
- super ConfigTree
+ super IniConfig
- # Kind of options used by this config
- type OPTIONS: AppOptions
+ redef var default_config_file: String = "app.ini"
- # Default configuration file path
- var default_config_file: String = "app.ini"
+ # Host name to bind on (will overwrite the config one).
+ var opt_host = new OptionString("Host to bind the server on", "--host")
# Web app host name
#
# * key: `app.host`
# * default: `localhost`
- var app_host: String is lazy do return value_or_default("app.host", "localhost")
+ fun app_host: String do return opt_host.value or else ini["app.host"] or else "localhost"
+
+ # Port number to bind on (will overwrite the config one).
+ var opt_port = new OptionInt("Port number to use", -1, "--port")
# Web app port
#
# * key: `app.port`
# * default: `3000`
- var app_port: Int is lazy do return value_or_default("app.port", "3000").to_i
-
- # Init `self` from a `AppOptions` option values
- init from_options(opts: OPTIONS) do
- init(opts.opt_config.value or else default_config_file)
- var opt_host = opts.opt_host.value
- if opt_host != null then self["app.host"] = opt_host
- var opt_port = opts.opt_port.value
- if opt_port > 0 then self["app.port"] = opt_port.to_s
+ fun app_port: Int do
+ var opt = opt_port.value
+ if opt > -1 then return opt
+ var val = ini["app.port"]
+ if val != null then return val.to_i
+ return 3000
end
- # Return the registered value for `key` or `default`
- protected fun value_or_default(key: String, default: String): String do
- return self[key] or else default
- end
-end
-
-# Options configuration for Popcorn apps
-#
-# Use the `AppOptions` class in your app to parse command line args:
-# ~~~
-# import popcorn
-# import popcorn::pop_config
-#
-# # Parse app options
-# var opts = new AppOptions.from_args(args)
-#
-# # Build config from options
-# var config = new AppConfig.from_options(opts)
-#
-# # Use options
-# var app = new App
-# app.listen(config.app_host, config.app_port)
-# ~~~
-class AppOptions
- super OptionContext
-
- # Help option.
- var opt_help = new OptionBool("Show this help message", "-h", "--help")
-
- # Path to app config file.
- var opt_config = new OptionString("Path to app config file", "--config")
-
- # Host name to bind on (will overwrite the config one).
- var opt_host = new OptionString("Host to bind the server on", "--host")
-
- # Port number to bind on (will overwrite the config one).
- var opt_port = new OptionInt("Port number to use", -1, "--port")
-
- # You should redefined this method to add your options
init do
super
- add_option(opt_help, opt_config, opt_host, opt_port)
- end
-
- # Initialize `self` and parse `args`
- init from_args(args: Collection[String]) do
- init
- parse(args)
+ add_option(opt_host, opt_port)
end
end
# Default database hostname
var default_db_name = "popcorn"
- # MongoDB server used for data persistence
- var db_host: String is lazy do return value_or_default("db.host", default_db_host)
-
- # MongoDB DB used for data persistence
- var db_name: String is lazy do return value_or_default("db.name", default_db_name)
-
- # Mongo db client
- var client = new MongoClient(db_host) is lazy
-
- # Mongo db instance
- var db: MongoDb = client.database(db_name) is lazy
-
- redef init from_options(opts) do
- super
- var db_host = opts.opt_db_host.value
- if db_host != null then self["db.host"] = db_host
- var db_name = opts.opt_db_name.value
- if db_name != null then self["db.name"] = db_name
- end
-end
-
-redef class AppOptions
-
# MongoDb host name
var opt_db_host = new OptionString("MongoDb host", "--db-host")
# MongoDb database name
var opt_db_name = new OptionString("MongoDb database name", "--db-name")
+ # MongoDB server used for data persistence
+ fun db_host: String do return opt_db_host.value or else ini["db.host"] or else default_db_host
+
+ # MongoDB DB used for data persistence
+ fun db_name: String do return opt_db_name.value or else ini["db.name"] or else default_db_name
+
init do
super
add_option(opt_db_host, opt_db_name)
end
+
+ # Mongo db client
+ var client = new MongoClient(db_host) is lazy
+
+ # Mongo db instance
+ var db: MongoDb = client.database(db_name) is lazy
end
# A Repository is an object that can store serialized instances.
<span>
- <a ng-href='{{mentity.web_url}}'>{{mentity.name}}</a>
+ <a ng-href='{{mentity.web_url | encodeURI}}'>{{mentity.name}}</a>
</span>
-<span ng-if='mentity.location'>
- <a ng-href="{{mentity.web_url}}">{{mentity.location.file}}
- <span ng-if='mentity.location.line_start'>:{{mentity.location.line_start}}</span>
- </a>
+<span ng-if='mentity.location' class='text-muted'>
+ {{mentity.location.file}}
+ <span ng-if='mentity.location.line_start'>:{{mentity.location.line_start}}</span>
</span>
--- /dev/null
+<h4>Grade this entity</h4>
+
+<div class='container-fluid'>
+ <div class='col-xs-8'>
+ <dl class='dl-horizontal'>
+ <dt>Feature</dt>
+ <dd>
+ <entity-stars mentity='mentity' dimension='feature' mean='ratings.feature.mean' list='ratings.feature.ratings' user='ratings.feature.user' ratings='ratings' />
+ <p class='text-muted'><i>This entity is useful, usable and has a good API. It helps me getting things done.</i></p>
+ </dd>
+ <dt>Documentation</dt>
+ <dd>
+ <entity-stars mentity='mentity' dimension='doc' mean='ratings.doc.mean' list='ratings.doc.ratings' user='ratings.doc.user' ratings='ratings' />
+ <p class='text-muted'><i>This entity is well documented, the explanations are clear and useful. They help me understand the feature and how to use it.</i></p>
+ </dd>
+ <dt>Examples</dt>
+ <dd>
+ <entity-stars mentity='mentity' dimension='examples' mean='ratings.examples.mean' list='ratings.examples.ratings' user='ratings.examples.user' ratings='ratings' />
+ <p class='text-muted'><i>This entity is provided with examples, they are runnable and free of bugs. They help me understand the feature behavior and how to use it.</i></p>
+ </dd>
+ <dt>Code</dt>
+ <dd>
+ <entity-stars mentity='mentity' dimension='code' mean='ratings.code.mean' list='ratings.code.ratings' user='ratings.code.user' ratings='ratings' />
+ <p class='text-muted'><i>This entity is well coded and respects the Nit standards.</i></p>
+ </dd>
+ </dl>
+ </div>
+ <div class='col-xs-4'>
+ <h1 class='text-center'>
+ <span class='text-danger'>{{ratings.feature.mean + ratings.doc.mean + ratings.examples.mean + ratings.code.mean | number: 1}} / 20</span><br><small>{{ratings.ratings.length}} votes</small>
+ </h1>
+ </div>
+</div>
+
+<h4>History</h4>
+
+<table class='table'>
+ <tr ng-repeat='rating in ratings.ratings | orderBy: "-timestamp"'>
+ <td>{{rating.timestamp * 1000 | date: 'yy/MM/dd hh:mm a'}}</td>
+ <td>
+ <i>{{rating.user ? rating.user : "anon"}}<i>
+ </td>
+ <td>
+ rated the <b>{{rating.dimension}}</b>
+ </td>
+ <td>
+ <span class='stars' ng-repeat='star in [1, 2, 3, 4, 5]'>
+ <span
+ class='star glyphicon'
+ ng-class='star <= rating.rating? "glyphicon-star": "glyphicon-star-empty"' />
+ </span>
+ </td>
+ </tr>
+</table>
-<span class='stars' ng-repeat='star in [1, 2, 3, 4, 5]' ng-if='ratings' title='mean: {{ratings.mean}} ({{ratings.ratings.length}} stars)'>
+<span class='stars editable' ng-repeat='star in [1, 2, 3, 4, 5]' title='mean: {{mean ? mean : 0 | number: 1}} ({{ratings ? ratings.length : 0}} stars)'>
<span
class='star glyphicon'
- ng-class='star <= ratings.mean? "glyphicon-star": "glyphicon-star-empty"'
- ng-click='postStar(star)' />
+ ng-class='[star <= mean? "glyphicon-star": "glyphicon-star-empty", user.rating == star? "active": ""]'
+ ng-click='starsCtrl.postStar(star)' />
</span>
</a>
<ul class='dropdown-menu'>
<li><a href='/docdown'>DocDown</a></li>
+ <li><a href='/grades'>Grades</a></li>
</ul>
</li>
</ul>
<script src='/javascripts/docdown.js'></script>
<script src='/javascripts/metrics.js'></script>
<script src='/javascripts/users.js'></script>
+ <script src='/javascripts/grades.js'></script>
</body>
</html>
angular
.module('entities', ['ngSanitize', 'ui', 'model'])
- .controller('EntityCtrl', ['Model', 'Metrics', '$routeParams', '$scope', '$sce', function(Model, Metrics, $routeParams, $scope, $sce) {
+ .controller('EntityCtrl', ['Model', 'Metrics', 'Feedback', '$routeParams', '$scope', '$sce', function(Model, Metrics, Feedback, $routeParams, $scope, $sce) {
$scope.entityId = $routeParams.id;
this.loadEntityLinearization = function() {
};
})
- .directive('entityCard', function() {
+ .directive('entityCard', ['Feedback', function(Feedback) {
return {
restrict: 'E',
scope: {
templateUrl: '/directives/entity/card.html',
link: function ($scope, element, attrs) {
$scope.currentTab = $scope.defaultTab ? $scope.defaultTab : 'signature';
+
+ $scope.loadEntityStars = function() {
+ Feedback.loadEntityStars($scope.mentity.full_name,
+ function(data) {
+ $scope.ratings = data;
+ }, function(message, status) {
+ $scope.error = {message: message, status: status};
+ });
+ };
}
};
- })
+ }])
.directive('entityList', function() {
return {
};
}])
- .directive('entityRating', ['Feedback', function(Feedback, Code) {
+ .controller('StarsCtrl', ['Feedback', '$scope', function(Feedback, $scope) {
+ $ctrl = this;
+
+ this.postStar = function(rating) {
+ Feedback.postEntityStarDimension($scope.mentity.full_name,
+ $scope.dimension, rating,
+ function(data) {
+ $scope.mean = data.mean;
+ $scope.list = data.ratings;
+ $scope.user = data.user;
+ $ctrl.loadEntityStars($scope);
+ }, function(err) {
+ $scope.err = err;
+ });
+ }
+
+ this.loadEntityStars = function($scope) {
+ Feedback.loadEntityStars($scope.mentity.full_name,
+ function(data) {
+ $scope.ratings = data;
+ }, function(message, status) {
+ $scope.error = {message: message, status: status};
+ });
+ };
+ }])
+
+ .directive('entityRating', ['Feedback', function(Feedback) {
return {
restrict: 'E',
scope: {
- mentity: '='
+ mentity: '=',
+ ratings: '='
},
- templateUrl: '/directives/entity/stars.html',
- link: function ($scope, element, attrs) {
- $scope.postStar = function(rating) {
- Feedback.postEntityStar($scope.mentity.full_name, rating,
- function(data) {
- $scope.ratings = data;
- }, function(err) {
- $scope.err = err;
- });
- }
+ controller: 'StarsCtrl',
+ controllerAs: 'ratingsCtrl',
+ templateUrl: '/directives/entity/rating.html'
+ };
+ }])
- Feedback.loadEntityStars($scope.mentity.full_name,
- function(data) {
- $scope.ratings = data;
- }, function(err) {
- $scope.err = err;
- });
- }
+ .directive('entityStars', ['Feedback', function(Feedback) {
+ return {
+ restrict: 'E',
+ scope: {
+ mentity: '=',
+ dimension: '@',
+ mean: '=',
+ list: '=',
+ user: '=',
+ refresh: '=',
+ ratings: '='
+ },
+ controller: 'StarsCtrl',
+ controllerAs: 'starsCtrl',
+ templateUrl: '/directives/entity/stars.html'
};
}])
})();
--- /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() {
+ angular
+ .module('grades', ['ngSanitize', 'model'])
+
+ .controller('GradesCtrl', ['Feedback', '$scope', function(Feedback, $scope) {
+
+ this.loadMostRated = function() {
+ Feedback.loadMostRated(
+ function(data) {
+ $scope.most = data;
+ }, function(err) {
+ $scope.error = err;
+ });
+ };
+
+ this.loadBestRated = function() {
+ Feedback.loadBestRated(
+ function(data) {
+ $scope.best = data;
+ }, function(err) {
+ $scope.error = err;
+ });
+ };
+ this.loadWorstRated = function() {
+ Feedback.loadWorstRated(
+ function(data) {
+ $scope.worst = data;
+ }, function(err) {
+ $scope.error = err;
+ });
+ };
+ this.loadUsersRatings = function() {
+ Feedback.loadUsersRatings(
+ function(data) {
+ $scope.ratings = data;
+ }, function(err) {
+ $scope.error = err;
+ });
+ };
+
+ this.loadMostRated();
+ this.loadBestRated();
+ this.loadWorstRated();
+ this.loadUsersRatings();
+ }])
+})();
.success(cb)
.error(cbErr);
},
- postEntityStar: function(id, rating, cb, cbErr) {
- $http.post(apiUrl + '/feedback/stars/' + id, {rating: rating})
+ 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);
+ },
}
}])
$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'])
+ angular.module('nitweb', ['ngRoute', 'ngSanitize', 'angular-loading-bar', 'entities', 'docdown', 'index', 'metrics', 'users', 'grades'])
.config(['cfpLoadingBarProvider', function(cfpLoadingBarProvider) {
cfpLoadingBarProvider.includeSpinner = false;
}])
controller: 'DocdownCtrl',
controllerAs: 'docdownCtrl'
})
+ .when('/grades', {
+ templateUrl: 'views/grades.html',
+ controller: 'GradesCtrl',
+ controllerAs: 'gradesCtrl'
+ })
.when('/login', {
controller : function(){
window.location.replace('/login');
templateUrl: 'views/error.html'
});
$locationProvider.html5Mode(true);
+ })
+
+ .filter('encodeURI', function() {
+ return encodeURIComponent;
});
})();
$scope.error = err;
});
};
-
+ this.loadGrades = function() {
+ User.loadUserStars(
+ function(data) {
+ $scope.ratings = data;
+ }, function(err) {
+ $scope.error = err;
+ });
+ };
this.loadUser();
+ this.loadGrades();
}])
.directive('userMenu', ['User', function(User) {
* Ratings
*/
-.card .stars {
- visibility: hidden
-}
-
-.card:hover .stars {
- visibility: visible
-}
-
.star {
color: grey;
+}
+
+.editable .star {
cursor: pointer;
}
-.star:hover, .star.active:hover {
+.editable .star:hover, .editable .star.active:hover {
color: #FF8100
}
<span class='glyphicon glyphicon-arrow-down'/> Linearization
</a>
</li>
- <li role='presentation'>
- <a data-toggle='tab' data-target='#code' ng-click="entityCtrl.loadEntityCode()">
- <span class='glyphicon glyphicon-console'/> Code
- </a>
- </li>
</ul>
<div class='tab-content'>
list-entities='linearization'
list-focus='mentity' />
</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>
--- /dev/null
+<div class='container-fluid'>
+ <div class='page-header'>
+ <h2>Grades</h2>
+
+ <div class='container-fluid'>
+ <div class='col-xs-6'>
+ <div class='card'>
+ <div class='card-body'>
+ <h4 class='card-title'>Most rated entities</h4>
+ <p ng-if='!most || most.length == 0' class='text-muted'>
+ <i>No grades yet</i>
+ </p>
+ <table class='table' ng-if='most.length > 0'>
+ <tr>
+ <th width='60%'>Entity</th>
+ <th>Total grades</th>
+ </tr>
+ <tr ng-repeat='rating in most'>
+ <th><a href='/doc/{{rating._id}}'>{{rating._id}}</a></th>
+ <td>{{rating.count}}</td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class='col-xs-6'>
+ <div class='card'>
+ <div class='card-body'>
+ <h4 class='card-title'>Best rated entities</h4>
+ <p ng-if='!best || best.length == 0' class='text-muted'>
+ <i>No grades yet</i>
+ </p>
+ <table class='table' ng-if='best.length > 0'>
+ <tr>
+ <th width='60%'>Entity</th>
+ <th>Avg. grade</th>
+ </tr>
+ <tr ng-repeat='rating in best'>
+ <th><a href='/doc/{{rating._id}}'>{{rating._id}}</a></th>
+ <td>{{rating.avg}}</td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class='col-xs-6'>
+ <div class='card'>
+ <div class='card-body'>
+ <h4 class='card-title'>Most active users</h4>
+ <p ng-if='!ratings || ratings.length == 0' class='text-muted'>
+ <i>No grades yet</i>
+ </p>
+ <table class='table' ng-if='ratings.length > 0'>
+ <tr>
+ <th width='60%'>User</th>
+ <th>Total grades</th>
+ </tr>
+ <tr ng-repeat='rating in ratings'>
+ <th ng-if='rating._id'>
+ <b>{{rating._id}}</b>
+ </th>
+ <th ng-if='!rating._id'>
+ <em>anon.</em>
+ </th>
+ <td>{{rating.count}}</td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class='col-xs-6'>
+ <div class='card'>
+ <div class='card-body'>
+ <h4 class='card-title'>Worst rated entities</h4>
+ <p ng-if='!worst || worst.length == 0' class='text-muted'>
+ <i>No grades yet</i>
+ </p>
+ <table class='table' ng-if='worst.length > 0'>
+ <tr>
+ <th width='60%'>Entity</th>
+ <th>Total grades</th>
+ </tr>
+ <tr ng-repeat='rating in worst'>
+ <th><a href='/doc/{{rating._id}}'>{{rating._id}}</a></th>
+ <td>{{rating.avg}}</td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
<span class='glyphicon glyphicon-arrow-down'/> Linearization
</a>
</li>
- <li role='presentation'>
- <a data-toggle='tab' data-target='#code' ng-click="entityCtrl.loadEntityCode()">
- <span class='glyphicon glyphicon-console'/> Code
- </a>
- </li>
</ul>
<div class='tab-content'>
list-entities='linearization'
list-focus='mentity' />
</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>
</ul>
</div>
<div class='col-xs-8'>
- Nothing to display yet.
+ <h4>Your grades</h4>
+
+ <table class='table'>
+ <tr ng-repeat='rating in ratings | orderBy: "-timestamp"'>
+ <td>{{rating.timestamp * 1000 | date: 'yy/MM/dd hh:mm a'}}</td>
+ <td>
+ <b><a href='/doc/{{rating.mentity}}'>{{rating.mentity}}</a></b>
+ </td>
+ <td>
+ <b>{{rating.dimension}}</b>
+ </td>
+ <td>
+ <span class='stars' ng-repeat='star in [1, 2, 3, 4, 5]'>
+ <span class='star glyphicon'
+ ng-class='star <= rating.rating? "glyphicon-star": "glyphicon-star-empty"' />
+ </span>
+ </td>
+ </tr>
+ </table>
</div>
<div>
# Same as `to_full_json` but with pretty json.
fun to_pretty_full_json: String do return serialize_to_full_json(plain=true, pretty=true)
+
+ # Sort mentities by name
+ private fun sort_entities(mentities: Collection[MEntity]): Array[MEntity] do
+ var sorter = new MEntityNameSorter
+ var sorted = mentities.to_a
+ sorter.sort(sorted)
+ return sorted
+ end
end
redef class MDoc
super
if v isa FullJsonSerializer then
v.serialize_attribute("root", to_mentity_ref(root))
- v.serialize_attribute("mgroups", to_mentity_refs(mgroups))
+ v.serialize_attribute("mgroups", to_mentity_refs(sort_entities(mgroups)))
var ini = self.ini
if ini != null then v.serialize_attribute("ini", ini.to_map)
end
v.serialize_attribute("mpackage", to_mentity_ref(mpackage))
v.serialize_attribute("default_mmodule", to_mentity_ref(default_mmodule))
v.serialize_attribute("parent", to_mentity_ref(parent))
- v.serialize_attribute("mmodules", to_mentity_refs(mmodules))
- v.serialize_attribute("mgroups", to_mentity_refs(in_nesting.direct_smallers))
+ v.serialize_attribute("mmodules", to_mentity_refs(sort_entities(mmodules)))
+ v.serialize_attribute("mgroups", to_mentity_refs(sort_entities(in_nesting.direct_smallers)))
end
end
end
var view = private_view
v.serialize_attribute("mpackage", to_mentity_ref(mpackage))
v.serialize_attribute("mgroup", to_mentity_ref(mgroup))
- v.serialize_attribute("intro_mclasses", to_mentity_refs(intro_mclasses))
- v.serialize_attribute("mclassdefs", to_mentity_refs(mclassdefs))
- v.serialize_attribute("intro_mclassdefs", to_mentity_refs(collect_intro_mclassdefs(view)))
- v.serialize_attribute("redef_mclassdefs", to_mentity_refs(collect_redef_mclassdefs(view)))
+ v.serialize_attribute("intro_mclasses", to_mentity_refs(sort_entities(intro_mclasses)))
+ v.serialize_attribute("mclassdefs", to_mentity_refs(sort_entities(mclassdefs)))
+ v.serialize_attribute("intro_mclassdefs", to_mentity_refs(sort_entities(collect_intro_mclassdefs(view))))
+ v.serialize_attribute("redef_mclassdefs", to_mentity_refs(sort_entities(collect_redef_mclassdefs(view))))
v.serialize_attribute("imports", to_mentity_refs(in_importation.direct_greaters))
end
end
v.serialize_attribute("intro_mmodule", to_mentity_ref(intro_mmodule))
v.serialize_attribute("mpackage", to_mentity_ref(intro_mmodule.mpackage))
v.serialize_attribute("mclassdefs", to_mentity_refs(mclassdefs))
- v.serialize_attribute("all_mproperties", to_mentity_refs(collect_accessible_mproperties(view)))
- v.serialize_attribute("intro_mproperties", to_mentity_refs(collect_intro_mproperties(view)))
- v.serialize_attribute("redef_mproperties", to_mentity_refs(collect_redef_mproperties(view)))
- v.serialize_attribute("parents", to_mentity_refs(collect_parents(view)))
+ v.serialize_attribute("all_mproperties", to_mentity_refs(sort_entities(collect_accessible_mproperties(view))))
+ v.serialize_attribute("intro_mproperties", to_mentity_refs(sort_entities(collect_intro_mproperties(view))))
+ v.serialize_attribute("redef_mproperties", to_mentity_refs(sort_entities(collect_redef_mproperties(view))))
+ v.serialize_attribute("parents", to_mentity_refs(sort_entities(collect_parents(view))))
end
end
end
var view = private_view
v.serialize_attribute("mmodule", to_mentity_ref(mmodule))
v.serialize_attribute("mclass", to_mentity_ref(mclass))
- v.serialize_attribute("mpropdefs", to_mentity_refs(mpropdefs))
- v.serialize_attribute("intro_mproperties", to_mentity_refs(intro_mproperties))
+ v.serialize_attribute("mpropdefs", to_mentity_refs(sort_entities(mpropdefs)))
+ v.serialize_attribute("intro_mproperties", to_mentity_refs(sort_entities(intro_mproperties)))
v.serialize_attribute("intro", to_mentity_ref(mclass.intro))
v.serialize_attribute("mpackage", to_mentity_ref(mmodule.mpackage))
- v.serialize_attribute("intro_mpropdefs", to_mentity_refs(collect_intro_mpropdefs(view)))
- v.serialize_attribute("redef_mpropdefs", to_mentity_refs(collect_redef_mpropdefs(view)))
+ v.serialize_attribute("intro_mpropdefs", to_mentity_refs(sort_entities(collect_intro_mpropdefs(view))))
+ v.serialize_attribute("redef_mpropdefs", to_mentity_refs(sort_entities(collect_redef_mpropdefs(view))))
end
end
end
if v isa FullJsonSerializer then
v.serialize_attribute("intro", to_mentity_ref(intro))
v.serialize_attribute("intro_mclassdef", to_mentity_ref(intro_mclassdef))
- v.serialize_attribute("mpropdefs", to_mentity_refs(mpropdefs))
+ v.serialize_attribute("mpropdefs", to_mentity_refs(sort_entities(mpropdefs)))
v.serialize_attribute("intro_mclass", to_mentity_ref(intro_mclassdef.mclass))
v.serialize_attribute("mpackage", to_mentity_ref(intro_mclassdef.mmodule.mpackage))
end
"full_name": "test_prog::Object"
},
"mpropdefs": [{
- "full_name": "test_prog$Object$OTHER"
+ "full_name": "test_prog$Object$!="
}, {
"full_name": "test_prog$Object$=="
}, {
- "full_name": "test_prog$Object$!="
+ "full_name": "test_prog$Object$OTHER"
}, {
"full_name": "test_prog$Object$init"
}],
"intro_mproperties": [{
- "full_name": "test_prog::Object::OTHER"
+ "full_name": "test_prog::Object::!="
}, {
"full_name": "test_prog::Object::=="
}, {
- "full_name": "test_prog::Object::!="
+ "full_name": "test_prog::Object::OTHER"
}, {
"full_name": "test_prog::Object::init"
}],
"full_name": "test_prog"
},
"intro_mpropdefs": [{
- "full_name": "test_prog$Object$OTHER"
+ "full_name": "test_prog$Object$!="
}, {
"full_name": "test_prog$Object$=="
}, {
- "full_name": "test_prog$Object$!="
+ "full_name": "test_prog$Object$OTHER"
}, {
"full_name": "test_prog$Object$init"
}],
"full_name": "test_prog::Int"
},
"mpropdefs": [{
- "full_name": "test_prog$Int$unary -"
+ "full_name": "test_prog$Int$*"
}, {
"full_name": "test_prog$Int$+"
}, {
"full_name": "test_prog$Int$-"
}, {
- "full_name": "test_prog$Int$*"
- }, {
"full_name": "test_prog$Int$/"
}, {
"full_name": "test_prog$Int$>"
}, {
"full_name": "test_prog$Int$to_f"
+ }, {
+ "full_name": "test_prog$Int$unary -"
}],
"intro_mproperties": [{
- "full_name": "test_prog::Int::unary -"
+ "full_name": "test_prog::Int::*"
}, {
"full_name": "test_prog::Int::+"
}, {
"full_name": "test_prog::Int::-"
}, {
- "full_name": "test_prog::Int::*"
- }, {
"full_name": "test_prog::Int::/"
}, {
"full_name": "test_prog::Int::>"
}, {
"full_name": "test_prog::Int::to_f"
+ }, {
+ "full_name": "test_prog::Int::unary -"
}],
"intro": {
"full_name": "test_prog$Int"
"full_name": "test_prog"
},
"intro_mpropdefs": [{
- "full_name": "test_prog$Int$unary -"
+ "full_name": "test_prog$Int$*"
}, {
"full_name": "test_prog$Int$+"
}, {
"full_name": "test_prog$Int$-"
}, {
- "full_name": "test_prog$Int$*"
- }, {
"full_name": "test_prog$Int$/"
}, {
"full_name": "test_prog$Int$>"
}, {
"full_name": "test_prog$Int$to_f"
+ }, {
+ "full_name": "test_prog$Int$unary -"
}],
"redef_mpropdefs": []
}
"full_name": "test_prog::Float"
},
"mpropdefs": [{
+ "full_name": "test_prog$Float$*"
+ }, {
"full_name": "test_prog$Float$+"
}, {
"full_name": "test_prog$Float$-"
}, {
- "full_name": "test_prog$Float$*"
- }, {
"full_name": "test_prog$Float$/"
}, {
"full_name": "test_prog$Float$>"
}],
"intro_mproperties": [{
+ "full_name": "test_prog::Float::*"
+ }, {
"full_name": "test_prog::Float::+"
}, {
"full_name": "test_prog::Float::-"
}, {
- "full_name": "test_prog::Float::*"
- }, {
"full_name": "test_prog::Float::/"
}, {
"full_name": "test_prog::Float::>"
"full_name": "test_prog"
},
"intro_mpropdefs": [{
+ "full_name": "test_prog$Float$*"
+ }, {
"full_name": "test_prog$Float$+"
}, {
"full_name": "test_prog$Float$-"
}, {
- "full_name": "test_prog$Float$*"
- }, {
"full_name": "test_prog$Float$/"
}, {
"full_name": "test_prog$Float$>"
"full_name": "test_prog::Career"
},
"mpropdefs": [{
- "full_name": "test_prog$Career$_strength_bonus"
- }, {
- "full_name": "test_prog$Career$strength_bonus"
+ "full_name": "test_prog$Career$_endurance_bonus"
}, {
- "full_name": "test_prog$Career$strength_bonus="
+ "full_name": "test_prog$Career$_intelligence_bonus"
}, {
- "full_name": "test_prog$Career$_endurance_bonus"
+ "full_name": "test_prog$Career$_strength_bonus"
}, {
"full_name": "test_prog$Career$endurance_bonus"
}, {
"full_name": "test_prog$Career$endurance_bonus="
}, {
- "full_name": "test_prog$Career$_intelligence_bonus"
+ "full_name": "test_prog$Career$Object::init"
}, {
"full_name": "test_prog$Career$intelligence_bonus"
}, {
"full_name": "test_prog$Career$intelligence_bonus="
}, {
- "full_name": "test_prog$Career$Object::init"
+ "full_name": "test_prog$Career$strength_bonus"
+ }, {
+ "full_name": "test_prog$Career$strength_bonus="
}],
"intro_mproperties": [{
- "full_name": "test_prog::careers::Career::_strength_bonus"
- }, {
- "full_name": "test_prog::Career::strength_bonus"
+ "full_name": "test_prog::careers::Career::_endurance_bonus"
}, {
- "full_name": "test_prog::Career::strength_bonus="
+ "full_name": "test_prog::careers::Career::_intelligence_bonus"
}, {
- "full_name": "test_prog::careers::Career::_endurance_bonus"
+ "full_name": "test_prog::careers::Career::_strength_bonus"
}, {
"full_name": "test_prog::Career::endurance_bonus"
}, {
"full_name": "test_prog::Career::endurance_bonus="
}, {
- "full_name": "test_prog::careers::Career::_intelligence_bonus"
- }, {
"full_name": "test_prog::Career::intelligence_bonus"
}, {
"full_name": "test_prog::Career::intelligence_bonus="
+ }, {
+ "full_name": "test_prog::Career::strength_bonus"
+ }, {
+ "full_name": "test_prog::Career::strength_bonus="
}],
"intro": {
"full_name": "test_prog$Career"
"full_name": "test_prog"
},
"intro_mpropdefs": [{
- "full_name": "test_prog$Career$_strength_bonus"
- }, {
- "full_name": "test_prog$Career$strength_bonus"
+ "full_name": "test_prog$Career$_endurance_bonus"
}, {
- "full_name": "test_prog$Career$strength_bonus="
+ "full_name": "test_prog$Career$_intelligence_bonus"
}, {
- "full_name": "test_prog$Career$_endurance_bonus"
+ "full_name": "test_prog$Career$_strength_bonus"
}, {
"full_name": "test_prog$Career$endurance_bonus"
}, {
"full_name": "test_prog$Career$endurance_bonus="
}, {
- "full_name": "test_prog$Career$_intelligence_bonus"
- }, {
"full_name": "test_prog$Career$intelligence_bonus"
}, {
"full_name": "test_prog$Career$intelligence_bonus="
+ }, {
+ "full_name": "test_prog$Career$strength_bonus"
+ }, {
+ "full_name": "test_prog$Career$strength_bonus="
}],
"redef_mpropdefs": [{
"full_name": "test_prog$Career$Object::init"
"full_name": "test_prog::Race"
},
"mpropdefs": [{
- "full_name": "test_prog$Race$_base_strength"
- }, {
- "full_name": "test_prog$Race$base_strength"
+ "full_name": "test_prog$Race$_base_endurance"
}, {
- "full_name": "test_prog$Race$base_strength="
+ "full_name": "test_prog$Race$_base_intelligence"
}, {
- "full_name": "test_prog$Race$_base_endurance"
+ "full_name": "test_prog$Race$_base_strength"
}, {
"full_name": "test_prog$Race$base_endurance"
}, {
"full_name": "test_prog$Race$base_endurance="
}, {
- "full_name": "test_prog$Race$_base_intelligence"
- }, {
"full_name": "test_prog$Race$base_intelligence"
}, {
"full_name": "test_prog$Race$base_intelligence="
}, {
+ "full_name": "test_prog$Race$base_strength"
+ }, {
+ "full_name": "test_prog$Race$base_strength="
+ }, {
"full_name": "test_prog$Race$Object::init"
}],
"intro_mproperties": [{
- "full_name": "test_prog::races::Race::_base_strength"
- }, {
- "full_name": "test_prog::Race::base_strength"
+ "full_name": "test_prog::races::Race::_base_endurance"
}, {
- "full_name": "test_prog::Race::base_strength="
+ "full_name": "test_prog::races::Race::_base_intelligence"
}, {
- "full_name": "test_prog::races::Race::_base_endurance"
+ "full_name": "test_prog::races::Race::_base_strength"
}, {
"full_name": "test_prog::Race::base_endurance"
}, {
"full_name": "test_prog::Race::base_endurance="
}, {
- "full_name": "test_prog::races::Race::_base_intelligence"
- }, {
"full_name": "test_prog::Race::base_intelligence"
}, {
"full_name": "test_prog::Race::base_intelligence="
+ }, {
+ "full_name": "test_prog::Race::base_strength"
+ }, {
+ "full_name": "test_prog::Race::base_strength="
}],
"intro": {
"full_name": "test_prog$Race"
"full_name": "test_prog"
},
"intro_mpropdefs": [{
- "full_name": "test_prog$Race$_base_strength"
- }, {
- "full_name": "test_prog$Race$base_strength"
+ "full_name": "test_prog$Race$_base_endurance"
}, {
- "full_name": "test_prog$Race$base_strength="
+ "full_name": "test_prog$Race$_base_intelligence"
}, {
- "full_name": "test_prog$Race$_base_endurance"
+ "full_name": "test_prog$Race$_base_strength"
}, {
"full_name": "test_prog$Race$base_endurance"
}, {
"full_name": "test_prog$Race$base_endurance="
}, {
- "full_name": "test_prog$Race$_base_intelligence"
- }, {
"full_name": "test_prog$Race$base_intelligence"
}, {
"full_name": "test_prog$Race$base_intelligence="
+ }, {
+ "full_name": "test_prog$Race$base_strength"
+ }, {
+ "full_name": "test_prog$Race$base_strength="
}],
"redef_mpropdefs": [{
"full_name": "test_prog$Race$Object::init"
"full_name": "test_prog::Character"
},
"mpropdefs": [{
+ "full_name": "test_prog$Character$_age"
+ }, {
+ "full_name": "test_prog$Character$_career"
+ }, {
+ "full_name": "test_prog$Character$_health"
+ }, {
+ "full_name": "test_prog$Character$_name"
+ }, {
"full_name": "test_prog$Character$_race"
}, {
- "full_name": "test_prog$Character$race"
+ "full_name": "test_prog$Character$_sex"
}, {
- "full_name": "test_prog$Character$race="
+ "full_name": "test_prog$Character$age"
}, {
- "full_name": "test_prog$Character$_career"
+ "full_name": "test_prog$Character$age="
}, {
"full_name": "test_prog$Character$career"
}, {
"full_name": "test_prog$Character$career="
}, {
- "full_name": "test_prog$Character$quit"
+ "full_name": "test_prog$Character$health"
}, {
- "full_name": "test_prog$Character$_name"
+ "full_name": "test_prog$Character$health="
+ }, {
+ "full_name": "test_prog$Character$Object::init"
+ }, {
+ "full_name": "test_prog$Character$max_health"
}, {
"full_name": "test_prog$Character$name"
}, {
"full_name": "test_prog$Character$name="
}, {
- "full_name": "test_prog$Character$_age"
- }, {
- "full_name": "test_prog$Character$age"
+ "full_name": "test_prog$Character$quit"
}, {
- "full_name": "test_prog$Character$age="
+ "full_name": "test_prog$Character$race"
}, {
- "full_name": "test_prog$Character$_sex"
+ "full_name": "test_prog$Character$race="
}, {
"full_name": "test_prog$Character$sex"
}, {
"full_name": "test_prog$Character$sex="
}, {
- "full_name": "test_prog$Character$total_strengh"
- }, {
"full_name": "test_prog$Character$total_endurance"
}, {
"full_name": "test_prog$Character$total_intelligence"
}, {
- "full_name": "test_prog$Character$max_health"
+ "full_name": "test_prog$Character$total_strengh"
+ }],
+ "intro_mproperties": [{
+ "full_name": "test_prog::character::Character::_age"
}, {
- "full_name": "test_prog$Character$_health"
+ "full_name": "test_prog::character::Character::_career"
}, {
- "full_name": "test_prog$Character$health"
+ "full_name": "test_prog::character::Character::_health"
}, {
- "full_name": "test_prog$Character$health="
+ "full_name": "test_prog::character::Character::_name"
}, {
- "full_name": "test_prog$Character$Object::init"
- }],
- "intro_mproperties": [{
"full_name": "test_prog::character::Character::_race"
}, {
- "full_name": "test_prog::Character::race"
+ "full_name": "test_prog::character::Character::_sex"
}, {
- "full_name": "test_prog::Character::race="
+ "full_name": "test_prog::Character::age"
}, {
- "full_name": "test_prog::character::Character::_career"
+ "full_name": "test_prog::Character::age="
}, {
"full_name": "test_prog::Character::career"
}, {
"full_name": "test_prog::Character::career="
}, {
- "full_name": "test_prog::Character::quit"
+ "full_name": "test_prog::Character::health"
}, {
- "full_name": "test_prog::character::Character::_name"
+ "full_name": "test_prog::Character::health="
+ }, {
+ "full_name": "test_prog::Character::max_health"
}, {
"full_name": "test_prog::Character::name"
}, {
"full_name": "test_prog::Character::name="
}, {
- "full_name": "test_prog::character::Character::_age"
- }, {
- "full_name": "test_prog::Character::age"
+ "full_name": "test_prog::Character::quit"
}, {
- "full_name": "test_prog::Character::age="
+ "full_name": "test_prog::Character::race"
}, {
- "full_name": "test_prog::character::Character::_sex"
+ "full_name": "test_prog::Character::race="
}, {
"full_name": "test_prog::Character::sex"
}, {
"full_name": "test_prog::Character::sex="
}, {
- "full_name": "test_prog::Character::total_strengh"
- }, {
"full_name": "test_prog::Character::total_endurance"
}, {
"full_name": "test_prog::Character::total_intelligence"
}, {
- "full_name": "test_prog::Character::max_health"
- }, {
- "full_name": "test_prog::character::Character::_health"
- }, {
- "full_name": "test_prog::Character::health"
- }, {
- "full_name": "test_prog::Character::health="
+ "full_name": "test_prog::Character::total_strengh"
}],
"intro": {
"full_name": "test_prog$Character"
"full_name": "test_prog"
},
"intro_mpropdefs": [{
+ "full_name": "test_prog$Character$_age"
+ }, {
+ "full_name": "test_prog$Character$_career"
+ }, {
+ "full_name": "test_prog$Character$_health"
+ }, {
+ "full_name": "test_prog$Character$_name"
+ }, {
"full_name": "test_prog$Character$_race"
}, {
- "full_name": "test_prog$Character$race"
+ "full_name": "test_prog$Character$_sex"
}, {
- "full_name": "test_prog$Character$race="
+ "full_name": "test_prog$Character$age"
}, {
- "full_name": "test_prog$Character$_career"
+ "full_name": "test_prog$Character$age="
}, {
"full_name": "test_prog$Character$career"
}, {
"full_name": "test_prog$Character$career="
}, {
- "full_name": "test_prog$Character$quit"
+ "full_name": "test_prog$Character$health"
}, {
- "full_name": "test_prog$Character$_name"
+ "full_name": "test_prog$Character$health="
+ }, {
+ "full_name": "test_prog$Character$max_health"
}, {
"full_name": "test_prog$Character$name"
}, {
"full_name": "test_prog$Character$name="
}, {
- "full_name": "test_prog$Character$_age"
- }, {
- "full_name": "test_prog$Character$age"
+ "full_name": "test_prog$Character$quit"
}, {
- "full_name": "test_prog$Character$age="
+ "full_name": "test_prog$Character$race"
}, {
- "full_name": "test_prog$Character$_sex"
+ "full_name": "test_prog$Character$race="
}, {
"full_name": "test_prog$Character$sex"
}, {
"full_name": "test_prog$Character$sex="
}, {
- "full_name": "test_prog$Character$total_strengh"
- }, {
"full_name": "test_prog$Character$total_endurance"
}, {
"full_name": "test_prog$Character$total_intelligence"
}, {
- "full_name": "test_prog$Character$max_health"
- }, {
- "full_name": "test_prog$Character$_health"
- }, {
- "full_name": "test_prog$Character$health"
- }, {
- "full_name": "test_prog$Character$health="
+ "full_name": "test_prog$Character$total_strengh"
}],
"redef_mpropdefs": [{
"full_name": "test_prog$Character$Object::init"
"full_name": "test_prog::Combatable"
},
"mpropdefs": [{
- "full_name": "test_prog$Combatable$hit_points"
- }, {
"full_name": "test_prog$Combatable$attack"
}, {
+ "full_name": "test_prog$Combatable$defend"
+ }, {
"full_name": "test_prog$Combatable$direct_attack"
}, {
- "full_name": "test_prog$Combatable$defend"
+ "full_name": "test_prog$Combatable$hit_points"
}, {
"full_name": "test_prog$Combatable$is_dead"
}],
"intro_mproperties": [{
- "full_name": "test_prog::Combatable::hit_points"
- }, {
"full_name": "test_prog::Combatable::attack"
}, {
+ "full_name": "test_prog::Combatable::defend"
+ }, {
"full_name": "test_prog::Combatable::direct_attack"
}, {
- "full_name": "test_prog::Combatable::defend"
+ "full_name": "test_prog::Combatable::hit_points"
}, {
"full_name": "test_prog::Combatable::is_dead"
}],
"full_name": "test_prog"
},
"intro_mpropdefs": [{
- "full_name": "test_prog$Combatable$hit_points"
- }, {
"full_name": "test_prog$Combatable$attack"
}, {
+ "full_name": "test_prog$Combatable$defend"
+ }, {
"full_name": "test_prog$Combatable$direct_attack"
}, {
- "full_name": "test_prog$Combatable$defend"
+ "full_name": "test_prog$Combatable$hit_points"
}, {
"full_name": "test_prog$Combatable$is_dead"
}],
"full_name": "test_prog::Game"
},
"mpropdefs": [{
- "full_name": "test_prog$Game$player_characters"
- }, {
"full_name": "test_prog$Game$computer_characters"
}, {
- "full_name": "test_prog$Game$start_game"
- }, {
"full_name": "test_prog$Game$pause_game"
}, {
+ "full_name": "test_prog$Game$player_characters"
+ }, {
+ "full_name": "test_prog$Game$start_game"
+ }, {
"full_name": "test_prog$Game$stop_game"
}],
"intro_mproperties": [{
- "full_name": "test_prog::Game::player_characters"
- }, {
"full_name": "test_prog::Game::computer_characters"
}, {
- "full_name": "test_prog::Game::start_game"
- }, {
"full_name": "test_prog::Game::pause_game"
}, {
+ "full_name": "test_prog::Game::player_characters"
+ }, {
+ "full_name": "test_prog::Game::start_game"
+ }, {
"full_name": "test_prog::Game::stop_game"
}],
"intro": {
"full_name": "test_prog"
},
"intro_mpropdefs": [{
- "full_name": "test_prog$Game$player_characters"
- }, {
"full_name": "test_prog$Game$computer_characters"
}, {
- "full_name": "test_prog$Game$start_game"
- }, {
"full_name": "test_prog$Game$pause_game"
}, {
+ "full_name": "test_prog$Game$player_characters"
+ }, {
+ "full_name": "test_prog$Game$start_game"
+ }, {
"full_name": "test_prog$Game$stop_game"
}],
"redef_mpropdefs": []
"full_name": "test_prog$Object"
}],
"all_mproperties": [{
- "full_name": "test_prog::Object::OTHER"
+ "full_name": "test_prog::Object::!="
}, {
"full_name": "test_prog::Object::=="
}, {
- "full_name": "test_prog::Object::!="
+ "full_name": "test_prog::Object::OTHER"
}, {
"full_name": "test_prog::Object::init"
}],
"intro_mproperties": [{
- "full_name": "test_prog::Object::OTHER"
+ "full_name": "test_prog::Object::!="
}, {
"full_name": "test_prog::Object::=="
}, {
- "full_name": "test_prog::Object::!="
+ "full_name": "test_prog::Object::OTHER"
}, {
"full_name": "test_prog::Object::init"
}],
"full_name": "test_prog$Int"
}],
"all_mproperties": [{
- "full_name": "test_prog::Int::unary -"
+ "full_name": "test_prog::Object::!="
+ }, {
+ "full_name": "test_prog::Int::*"
}, {
"full_name": "test_prog::Int::+"
}, {
"full_name": "test_prog::Int::-"
}, {
- "full_name": "test_prog::Int::*"
- }, {
"full_name": "test_prog::Int::/"
}, {
- "full_name": "test_prog::Int::>"
+ "full_name": "test_prog::Object::=="
}, {
- "full_name": "test_prog::Int::to_f"
+ "full_name": "test_prog::Int::>"
}, {
"full_name": "test_prog::Object::OTHER"
}, {
- "full_name": "test_prog::Object::=="
+ "full_name": "test_prog::Object::init"
}, {
- "full_name": "test_prog::Object::!="
+ "full_name": "test_prog::Int::to_f"
}, {
- "full_name": "test_prog::Object::init"
+ "full_name": "test_prog::Int::unary -"
}],
"intro_mproperties": [{
- "full_name": "test_prog::Int::unary -"
+ "full_name": "test_prog::Int::*"
}, {
"full_name": "test_prog::Int::+"
}, {
"full_name": "test_prog::Int::-"
}, {
- "full_name": "test_prog::Int::*"
- }, {
"full_name": "test_prog::Int::/"
}, {
"full_name": "test_prog::Int::>"
}, {
"full_name": "test_prog::Int::to_f"
+ }, {
+ "full_name": "test_prog::Int::unary -"
}],
"redef_mproperties": [],
"parents": [{
"full_name": "test_prog$Float"
}],
"all_mproperties": [{
+ "full_name": "test_prog::Object::!="
+ }, {
+ "full_name": "test_prog::Float::*"
+ }, {
"full_name": "test_prog::Float::+"
}, {
"full_name": "test_prog::Float::-"
}, {
- "full_name": "test_prog::Float::*"
- }, {
"full_name": "test_prog::Float::/"
}, {
+ "full_name": "test_prog::Object::=="
+ }, {
"full_name": "test_prog::Float::>"
}, {
"full_name": "test_prog::Object::OTHER"
}, {
- "full_name": "test_prog::Object::=="
- }, {
- "full_name": "test_prog::Object::!="
- }, {
"full_name": "test_prog::Object::init"
}],
"intro_mproperties": [{
+ "full_name": "test_prog::Float::*"
+ }, {
"full_name": "test_prog::Float::+"
}, {
"full_name": "test_prog::Float::-"
}, {
- "full_name": "test_prog::Float::*"
- }, {
"full_name": "test_prog::Float::/"
}, {
"full_name": "test_prog::Float::>"
"full_name": "test_prog$Bool"
}],
"all_mproperties": [{
- "full_name": "test_prog::Object::OTHER"
+ "full_name": "test_prog::Object::!="
}, {
"full_name": "test_prog::Object::=="
}, {
- "full_name": "test_prog::Object::!="
+ "full_name": "test_prog::Object::OTHER"
}, {
"full_name": "test_prog::Object::init"
}],
"full_name": "test_prog$String"
}],
"all_mproperties": [{
- "full_name": "test_prog::Object::OTHER"
+ "full_name": "test_prog::Object::!="
}, {
"full_name": "test_prog::Object::=="
}, {
- "full_name": "test_prog::Object::!="
+ "full_name": "test_prog::Object::OTHER"
}, {
"full_name": "test_prog::Object::init"
}],
"full_name": "test_prog$List"
}],
"all_mproperties": [{
- "full_name": "test_prog::Object::OTHER"
+ "full_name": "test_prog::Object::!="
}, {
"full_name": "test_prog::Object::=="
}, {
- "full_name": "test_prog::Object::!="
+ "full_name": "test_prog::Object::OTHER"
}, {
"full_name": "test_prog::Object::init"
}],
"full_name": "test_prog$Career"
}],
"all_mproperties": [{
- "full_name": "test_prog::careers::Career::_strength_bonus"
+ "full_name": "test_prog::Object::!="
}, {
- "full_name": "test_prog::Career::strength_bonus"
+ "full_name": "test_prog::Object::=="
}, {
- "full_name": "test_prog::Career::strength_bonus="
+ "full_name": "test_prog::Object::OTHER"
}, {
"full_name": "test_prog::careers::Career::_endurance_bonus"
}, {
+ "full_name": "test_prog::careers::Career::_intelligence_bonus"
+ }, {
+ "full_name": "test_prog::careers::Career::_strength_bonus"
+ }, {
"full_name": "test_prog::Career::endurance_bonus"
}, {
"full_name": "test_prog::Career::endurance_bonus="
}, {
- "full_name": "test_prog::careers::Career::_intelligence_bonus"
+ "full_name": "test_prog::Object::init"
}, {
"full_name": "test_prog::Career::intelligence_bonus"
}, {
"full_name": "test_prog::Career::intelligence_bonus="
}, {
- "full_name": "test_prog::Object::init"
- }, {
- "full_name": "test_prog::Object::OTHER"
- }, {
- "full_name": "test_prog::Object::=="
+ "full_name": "test_prog::Career::strength_bonus"
}, {
- "full_name": "test_prog::Object::!="
+ "full_name": "test_prog::Career::strength_bonus="
}],
"intro_mproperties": [{
- "full_name": "test_prog::careers::Career::_strength_bonus"
- }, {
- "full_name": "test_prog::Career::strength_bonus"
+ "full_name": "test_prog::careers::Career::_endurance_bonus"
}, {
- "full_name": "test_prog::Career::strength_bonus="
+ "full_name": "test_prog::careers::Career::_intelligence_bonus"
}, {
- "full_name": "test_prog::careers::Career::_endurance_bonus"
+ "full_name": "test_prog::careers::Career::_strength_bonus"
}, {
"full_name": "test_prog::Career::endurance_bonus"
}, {
"full_name": "test_prog::Career::endurance_bonus="
}, {
- "full_name": "test_prog::careers::Career::_intelligence_bonus"
- }, {
"full_name": "test_prog::Career::intelligence_bonus"
}, {
"full_name": "test_prog::Career::intelligence_bonus="
+ }, {
+ "full_name": "test_prog::Career::strength_bonus"
+ }, {
+ "full_name": "test_prog::Career::strength_bonus="
}],
"redef_mproperties": [{
"full_name": "test_prog::Object::init"
"full_name": "test_prog$Warrior"
}],
"all_mproperties": [{
- "full_name": "test_prog::Object::init"
- }, {
- "full_name": "test_prog::careers::Career::_strength_bonus"
+ "full_name": "test_prog::Object::!="
}, {
- "full_name": "test_prog::Career::strength_bonus"
+ "full_name": "test_prog::Object::=="
}, {
- "full_name": "test_prog::Career::strength_bonus="
+ "full_name": "test_prog::Object::OTHER"
}, {
"full_name": "test_prog::careers::Career::_endurance_bonus"
}, {
+ "full_name": "test_prog::careers::Career::_intelligence_bonus"
+ }, {
+ "full_name": "test_prog::careers::Career::_strength_bonus"
+ }, {
"full_name": "test_prog::Career::endurance_bonus"
}, {
"full_name": "test_prog::Career::endurance_bonus="
}, {
- "full_name": "test_prog::careers::Career::_intelligence_bonus"
+ "full_name": "test_prog::Object::init"
}, {
"full_name": "test_prog::Career::intelligence_bonus"
}, {
"full_name": "test_prog::Career::intelligence_bonus="
}, {
- "full_name": "test_prog::Object::OTHER"
- }, {
- "full_name": "test_prog::Object::=="
+ "full_name": "test_prog::Career::strength_bonus"
}, {
- "full_name": "test_prog::Object::!="
+ "full_name": "test_prog::Career::strength_bonus="
}],
"intro_mproperties": [],
"redef_mproperties": [{
"full_name": "test_prog$Magician"
}],
"all_mproperties": [{
- "full_name": "test_prog::Object::init"
- }, {
- "full_name": "test_prog::careers::Career::_strength_bonus"
+ "full_name": "test_prog::Object::!="
}, {
- "full_name": "test_prog::Career::strength_bonus"
+ "full_name": "test_prog::Object::=="
}, {
- "full_name": "test_prog::Career::strength_bonus="
+ "full_name": "test_prog::Object::OTHER"
}, {
"full_name": "test_prog::careers::Career::_endurance_bonus"
}, {
+ "full_name": "test_prog::careers::Career::_intelligence_bonus"
+ }, {
+ "full_name": "test_prog::careers::Career::_strength_bonus"
+ }, {
"full_name": "test_prog::Career::endurance_bonus"
}, {
"full_name": "test_prog::Career::endurance_bonus="
}, {
- "full_name": "test_prog::careers::Career::_intelligence_bonus"
+ "full_name": "test_prog::Object::init"
}, {
"full_name": "test_prog::Career::intelligence_bonus"
}, {
"full_name": "test_prog::Career::intelligence_bonus="
}, {
- "full_name": "test_prog::Object::OTHER"
- }, {
- "full_name": "test_prog::Object::=="
+ "full_name": "test_prog::Career::strength_bonus"
}, {
- "full_name": "test_prog::Object::!="
+ "full_name": "test_prog::Career::strength_bonus="
}],
"intro_mproperties": [],
"redef_mproperties": [{
"full_name": "test_prog$Alcoholic"
}],
"all_mproperties": [{
- "full_name": "test_prog::Object::init"
- }, {
- "full_name": "test_prog::careers::Career::_strength_bonus"
+ "full_name": "test_prog::Object::!="
}, {
- "full_name": "test_prog::Career::strength_bonus"
+ "full_name": "test_prog::Object::=="
}, {
- "full_name": "test_prog::Career::strength_bonus="
+ "full_name": "test_prog::Object::OTHER"
}, {
"full_name": "test_prog::careers::Career::_endurance_bonus"
}, {
+ "full_name": "test_prog::careers::Career::_intelligence_bonus"
+ }, {
+ "full_name": "test_prog::careers::Career::_strength_bonus"
+ }, {
"full_name": "test_prog::Career::endurance_bonus"
}, {
"full_name": "test_prog::Career::endurance_bonus="
}, {
- "full_name": "test_prog::careers::Career::_intelligence_bonus"
+ "full_name": "test_prog::Object::init"
}, {
"full_name": "test_prog::Career::intelligence_bonus"
}, {
"full_name": "test_prog::Career::intelligence_bonus="
}, {
- "full_name": "test_prog::Object::OTHER"
- }, {
- "full_name": "test_prog::Object::=="
+ "full_name": "test_prog::Career::strength_bonus"
}, {
- "full_name": "test_prog::Object::!="
+ "full_name": "test_prog::Career::strength_bonus="
}],
"intro_mproperties": [],
"redef_mproperties": [{
"full_name": "test_prog$Race"
}],
"all_mproperties": [{
- "full_name": "test_prog::races::Race::_base_strength"
+ "full_name": "test_prog::Object::!="
}, {
- "full_name": "test_prog::Race::base_strength"
+ "full_name": "test_prog::Object::=="
}, {
- "full_name": "test_prog::Race::base_strength="
+ "full_name": "test_prog::Object::OTHER"
}, {
"full_name": "test_prog::races::Race::_base_endurance"
}, {
+ "full_name": "test_prog::races::Race::_base_intelligence"
+ }, {
+ "full_name": "test_prog::races::Race::_base_strength"
+ }, {
"full_name": "test_prog::Race::base_endurance"
}, {
"full_name": "test_prog::Race::base_endurance="
}, {
- "full_name": "test_prog::races::Race::_base_intelligence"
- }, {
"full_name": "test_prog::Race::base_intelligence"
}, {
"full_name": "test_prog::Race::base_intelligence="
}, {
- "full_name": "test_prog::Object::init"
- }, {
- "full_name": "test_prog::Object::OTHER"
+ "full_name": "test_prog::Race::base_strength"
}, {
- "full_name": "test_prog::Object::=="
+ "full_name": "test_prog::Race::base_strength="
}, {
- "full_name": "test_prog::Object::!="
+ "full_name": "test_prog::Object::init"
}],
"intro_mproperties": [{
- "full_name": "test_prog::races::Race::_base_strength"
- }, {
- "full_name": "test_prog::Race::base_strength"
+ "full_name": "test_prog::races::Race::_base_endurance"
}, {
- "full_name": "test_prog::Race::base_strength="
+ "full_name": "test_prog::races::Race::_base_intelligence"
}, {
- "full_name": "test_prog::races::Race::_base_endurance"
+ "full_name": "test_prog::races::Race::_base_strength"
}, {
"full_name": "test_prog::Race::base_endurance"
}, {
"full_name": "test_prog::Race::base_endurance="
}, {
- "full_name": "test_prog::races::Race::_base_intelligence"
- }, {
"full_name": "test_prog::Race::base_intelligence"
}, {
"full_name": "test_prog::Race::base_intelligence="
+ }, {
+ "full_name": "test_prog::Race::base_strength"
+ }, {
+ "full_name": "test_prog::Race::base_strength="
}],
"redef_mproperties": [{
"full_name": "test_prog::Object::init"
"full_name": "test_prog$Human"
}],
"all_mproperties": [{
- "full_name": "test_prog::Object::init"
- }, {
- "full_name": "test_prog::races::Race::_base_strength"
+ "full_name": "test_prog::Object::!="
}, {
- "full_name": "test_prog::Race::base_strength"
+ "full_name": "test_prog::Object::=="
}, {
- "full_name": "test_prog::Race::base_strength="
+ "full_name": "test_prog::Object::OTHER"
}, {
"full_name": "test_prog::races::Race::_base_endurance"
}, {
+ "full_name": "test_prog::races::Race::_base_intelligence"
+ }, {
+ "full_name": "test_prog::races::Race::_base_strength"
+ }, {
"full_name": "test_prog::Race::base_endurance"
}, {
"full_name": "test_prog::Race::base_endurance="
}, {
- "full_name": "test_prog::races::Race::_base_intelligence"
- }, {
"full_name": "test_prog::Race::base_intelligence"
}, {
"full_name": "test_prog::Race::base_intelligence="
}, {
- "full_name": "test_prog::Object::OTHER"
+ "full_name": "test_prog::Race::base_strength"
}, {
- "full_name": "test_prog::Object::=="
+ "full_name": "test_prog::Race::base_strength="
}, {
- "full_name": "test_prog::Object::!="
+ "full_name": "test_prog::Object::init"
}],
"intro_mproperties": [],
"redef_mproperties": [{
"full_name": "test_prog::combat$Dwarf"
}],
"all_mproperties": [{
- "full_name": "test_prog::Object::init"
+ "full_name": "test_prog::Object::!="
}, {
- "full_name": "test_prog::Weapon::dps"
+ "full_name": "test_prog::Object::=="
}, {
- "full_name": "test_prog::races::Race::_base_strength"
+ "full_name": "test_prog::Object::OTHER"
}, {
- "full_name": "test_prog::Race::base_strength"
+ "full_name": "test_prog::races::Race::_base_endurance"
}, {
- "full_name": "test_prog::Race::base_strength="
+ "full_name": "test_prog::races::Race::_base_intelligence"
}, {
- "full_name": "test_prog::races::Race::_base_endurance"
+ "full_name": "test_prog::races::Race::_base_strength"
}, {
"full_name": "test_prog::Race::base_endurance"
}, {
"full_name": "test_prog::Race::base_endurance="
}, {
- "full_name": "test_prog::races::Race::_base_intelligence"
- }, {
"full_name": "test_prog::Race::base_intelligence"
}, {
"full_name": "test_prog::Race::base_intelligence="
}, {
- "full_name": "test_prog::Object::OTHER"
+ "full_name": "test_prog::Race::base_strength"
}, {
- "full_name": "test_prog::Object::=="
+ "full_name": "test_prog::Race::base_strength="
}, {
- "full_name": "test_prog::Object::!="
+ "full_name": "test_prog::Weapon::dps"
+ }, {
+ "full_name": "test_prog::Object::init"
}],
"intro_mproperties": [],
"redef_mproperties": [{
- "full_name": "test_prog::Object::init"
- }, {
"full_name": "test_prog::Weapon::dps"
+ }, {
+ "full_name": "test_prog::Object::init"
}],
"parents": [{
"full_name": "test_prog::Race"
"full_name": "test_prog$Elf"
}],
"all_mproperties": [{
- "full_name": "test_prog::Object::init"
- }, {
- "full_name": "test_prog::races::Race::_base_strength"
+ "full_name": "test_prog::Object::!="
}, {
- "full_name": "test_prog::Race::base_strength"
+ "full_name": "test_prog::Object::=="
}, {
- "full_name": "test_prog::Race::base_strength="
+ "full_name": "test_prog::Object::OTHER"
}, {
"full_name": "test_prog::races::Race::_base_endurance"
}, {
+ "full_name": "test_prog::races::Race::_base_intelligence"
+ }, {
+ "full_name": "test_prog::races::Race::_base_strength"
+ }, {
"full_name": "test_prog::Race::base_endurance"
}, {
"full_name": "test_prog::Race::base_endurance="
}, {
- "full_name": "test_prog::races::Race::_base_intelligence"
- }, {
"full_name": "test_prog::Race::base_intelligence"
}, {
"full_name": "test_prog::Race::base_intelligence="
}, {
- "full_name": "test_prog::Object::OTHER"
+ "full_name": "test_prog::Race::base_strength"
}, {
- "full_name": "test_prog::Object::=="
+ "full_name": "test_prog::Race::base_strength="
}, {
- "full_name": "test_prog::Object::!="
+ "full_name": "test_prog::Object::init"
}],
"intro_mproperties": [],
"redef_mproperties": [{
"full_name": "test_prog::combat$Character"
}],
"all_mproperties": [{
- "full_name": "test_prog::character::Character::_race"
- }, {
- "full_name": "test_prog::Character::race"
+ "full_name": "test_prog::Object::!="
}, {
- "full_name": "test_prog::Character::race="
+ "full_name": "test_prog::Object::=="
}, {
- "full_name": "test_prog::character::Character::_career"
+ "full_name": "test_prog::Object::OTHER"
}, {
- "full_name": "test_prog::Character::career"
+ "full_name": "test_prog::character::Character::_age"
}, {
- "full_name": "test_prog::Character::career="
+ "full_name": "test_prog::character::Character::_career"
}, {
- "full_name": "test_prog::Character::quit"
+ "full_name": "test_prog::character::Character::_health"
}, {
"full_name": "test_prog::character::Character::_name"
}, {
- "full_name": "test_prog::Character::name"
- }, {
- "full_name": "test_prog::Character::name="
+ "full_name": "test_prog::character::Character::_race"
}, {
- "full_name": "test_prog::character::Character::_age"
+ "full_name": "test_prog::character::Character::_sex"
}, {
"full_name": "test_prog::Character::age"
}, {
"full_name": "test_prog::Character::age="
}, {
- "full_name": "test_prog::character::Character::_sex"
- }, {
- "full_name": "test_prog::Character::sex"
- }, {
- "full_name": "test_prog::Character::sex="
- }, {
- "full_name": "test_prog::Character::total_strengh"
+ "full_name": "test_prog::Combatable::attack"
}, {
- "full_name": "test_prog::Character::total_endurance"
+ "full_name": "test_prog::Character::career"
}, {
- "full_name": "test_prog::Character::total_intelligence"
+ "full_name": "test_prog::Character::career="
}, {
- "full_name": "test_prog::Character::max_health"
+ "full_name": "test_prog::Combatable::defend"
}, {
- "full_name": "test_prog::character::Character::_health"
+ "full_name": "test_prog::Combatable::direct_attack"
}, {
"full_name": "test_prog::Character::health"
}, {
"full_name": "test_prog::Character::health="
}, {
+ "full_name": "test_prog::Combatable::hit_points"
+ }, {
"full_name": "test_prog::Object::init"
}, {
- "full_name": "test_prog::Combatable::hit_points"
+ "full_name": "test_prog::Combatable::is_dead"
}, {
- "full_name": "test_prog::Object::OTHER"
+ "full_name": "test_prog::Character::max_health"
}, {
- "full_name": "test_prog::Object::=="
+ "full_name": "test_prog::Character::name"
}, {
- "full_name": "test_prog::Object::!="
+ "full_name": "test_prog::Character::name="
}, {
- "full_name": "test_prog::Combatable::attack"
+ "full_name": "test_prog::Character::quit"
}, {
- "full_name": "test_prog::Combatable::direct_attack"
+ "full_name": "test_prog::Character::race"
}, {
- "full_name": "test_prog::Combatable::defend"
+ "full_name": "test_prog::Character::race="
}, {
- "full_name": "test_prog::Combatable::is_dead"
+ "full_name": "test_prog::Character::sex"
+ }, {
+ "full_name": "test_prog::Character::sex="
+ }, {
+ "full_name": "test_prog::Character::total_endurance"
+ }, {
+ "full_name": "test_prog::Character::total_intelligence"
+ }, {
+ "full_name": "test_prog::Character::total_strengh"
}],
"intro_mproperties": [{
+ "full_name": "test_prog::character::Character::_age"
+ }, {
+ "full_name": "test_prog::character::Character::_career"
+ }, {
+ "full_name": "test_prog::character::Character::_health"
+ }, {
+ "full_name": "test_prog::character::Character::_name"
+ }, {
"full_name": "test_prog::character::Character::_race"
}, {
- "full_name": "test_prog::Character::race"
+ "full_name": "test_prog::character::Character::_sex"
}, {
- "full_name": "test_prog::Character::race="
+ "full_name": "test_prog::Character::age"
}, {
- "full_name": "test_prog::character::Character::_career"
+ "full_name": "test_prog::Character::age="
}, {
"full_name": "test_prog::Character::career"
}, {
"full_name": "test_prog::Character::career="
}, {
- "full_name": "test_prog::Character::quit"
+ "full_name": "test_prog::Character::health"
}, {
- "full_name": "test_prog::character::Character::_name"
+ "full_name": "test_prog::Character::health="
+ }, {
+ "full_name": "test_prog::Character::max_health"
}, {
"full_name": "test_prog::Character::name"
}, {
"full_name": "test_prog::Character::name="
}, {
- "full_name": "test_prog::character::Character::_age"
- }, {
- "full_name": "test_prog::Character::age"
+ "full_name": "test_prog::Character::quit"
}, {
- "full_name": "test_prog::Character::age="
+ "full_name": "test_prog::Character::race"
}, {
- "full_name": "test_prog::character::Character::_sex"
+ "full_name": "test_prog::Character::race="
}, {
"full_name": "test_prog::Character::sex"
}, {
"full_name": "test_prog::Character::sex="
}, {
- "full_name": "test_prog::Character::total_strengh"
- }, {
"full_name": "test_prog::Character::total_endurance"
}, {
"full_name": "test_prog::Character::total_intelligence"
}, {
- "full_name": "test_prog::Character::max_health"
- }, {
- "full_name": "test_prog::character::Character::_health"
- }, {
- "full_name": "test_prog::Character::health"
- }, {
- "full_name": "test_prog::Character::health="
+ "full_name": "test_prog::Character::total_strengh"
}],
"redef_mproperties": [{
- "full_name": "test_prog::Object::init"
- }, {
"full_name": "test_prog::Combatable::hit_points"
+ }, {
+ "full_name": "test_prog::Object::init"
}],
"parents": [{
- "full_name": "test_prog::Object"
- }, {
"full_name": "test_prog::Combatable"
+ }, {
+ "full_name": "test_prog::Object"
}]
}
{
"full_name": "test_prog$Weapon"
}],
"all_mproperties": [{
- "full_name": "test_prog::Weapon::dps"
- }, {
- "full_name": "test_prog::Object::OTHER"
+ "full_name": "test_prog::Object::!="
}, {
"full_name": "test_prog::Object::=="
}, {
- "full_name": "test_prog::Object::!="
+ "full_name": "test_prog::Object::OTHER"
+ }, {
+ "full_name": "test_prog::Weapon::dps"
}, {
"full_name": "test_prog::Object::init"
}],
"full_name": "test_prog$Combatable"
}],
"all_mproperties": [{
- "full_name": "test_prog::Combatable::hit_points"
- }, {
- "full_name": "test_prog::Combatable::attack"
+ "full_name": "test_prog::Object::!="
}, {
- "full_name": "test_prog::Combatable::direct_attack"
+ "full_name": "test_prog::Object::=="
}, {
- "full_name": "test_prog::Combatable::defend"
+ "full_name": "test_prog::Object::OTHER"
}, {
- "full_name": "test_prog::Combatable::is_dead"
+ "full_name": "test_prog::Combatable::attack"
}, {
- "full_name": "test_prog::Object::OTHER"
+ "full_name": "test_prog::Combatable::defend"
}, {
- "full_name": "test_prog::Object::=="
+ "full_name": "test_prog::Combatable::direct_attack"
}, {
- "full_name": "test_prog::Object::!="
+ "full_name": "test_prog::Combatable::hit_points"
}, {
"full_name": "test_prog::Object::init"
+ }, {
+ "full_name": "test_prog::Combatable::is_dead"
}],
"intro_mproperties": [{
- "full_name": "test_prog::Combatable::hit_points"
- }, {
"full_name": "test_prog::Combatable::attack"
}, {
+ "full_name": "test_prog::Combatable::defend"
+ }, {
"full_name": "test_prog::Combatable::direct_attack"
}, {
- "full_name": "test_prog::Combatable::defend"
+ "full_name": "test_prog::Combatable::hit_points"
}, {
"full_name": "test_prog::Combatable::is_dead"
}],
"full_name": "test_prog$Game"
}],
"all_mproperties": [{
- "full_name": "test_prog::Game::player_characters"
+ "full_name": "test_prog::Object::!="
}, {
- "full_name": "test_prog::Game::computer_characters"
+ "full_name": "test_prog::Object::=="
}, {
- "full_name": "test_prog::Game::start_game"
+ "full_name": "test_prog::Object::OTHER"
}, {
- "full_name": "test_prog::Game::pause_game"
+ "full_name": "test_prog::Game::computer_characters"
}, {
- "full_name": "test_prog::Game::stop_game"
+ "full_name": "test_prog::Object::init"
}, {
- "full_name": "test_prog::Object::OTHER"
+ "full_name": "test_prog::Game::pause_game"
}, {
- "full_name": "test_prog::Object::=="
+ "full_name": "test_prog::Game::player_characters"
}, {
- "full_name": "test_prog::Object::!="
+ "full_name": "test_prog::Game::start_game"
}, {
- "full_name": "test_prog::Object::init"
+ "full_name": "test_prog::Game::stop_game"
}],
"intro_mproperties": [{
- "full_name": "test_prog::Game::player_characters"
- }, {
"full_name": "test_prog::Game::computer_characters"
}, {
- "full_name": "test_prog::Game::start_game"
- }, {
"full_name": "test_prog::Game::pause_game"
}, {
+ "full_name": "test_prog::Game::player_characters"
+ }, {
+ "full_name": "test_prog::Game::start_game"
+ }, {
"full_name": "test_prog::Game::stop_game"
}],
"redef_mproperties": [],
"full_name": "test_prog$Starter"
}],
"all_mproperties": [{
- "full_name": "test_prog::Starter::start"
- }, {
- "full_name": "test_prog::Object::OTHER"
+ "full_name": "test_prog::Object::!="
}, {
"full_name": "test_prog::Object::=="
}, {
- "full_name": "test_prog::Object::!="
+ "full_name": "test_prog::Object::OTHER"
}, {
"full_name": "test_prog::Object::init"
+ }, {
+ "full_name": "test_prog::Starter::start"
}],
"intro_mproperties": [{
"full_name": "test_prog::Starter::start"
"full_name": "test_prog$Sys"
}],
"all_mproperties": [{
- "full_name": "test_prog::Sys::main"
- }, {
- "full_name": "test_prog::Object::OTHER"
+ "full_name": "test_prog::Object::!="
}, {
"full_name": "test_prog::Object::=="
}, {
- "full_name": "test_prog::Object::!="
+ "full_name": "test_prog::Object::OTHER"
}, {
"full_name": "test_prog::Object::init"
+ }, {
+ "full_name": "test_prog::Sys::main"
}],
"intro_mproperties": [{
"full_name": "test_prog::Sys::main"
"full_name": "test_prog>platform>"
},
"intro_mclasses": [{
- "full_name": "test_prog::Object"
+ "full_name": "test_prog::Bool"
+ }, {
+ "full_name": "test_prog::Float"
}, {
"full_name": "test_prog::Int"
}, {
- "full_name": "test_prog::Float"
+ "full_name": "test_prog::List"
}, {
- "full_name": "test_prog::Bool"
+ "full_name": "test_prog::Object"
}, {
"full_name": "test_prog::String"
- }, {
- "full_name": "test_prog::List"
}],
"mclassdefs": [{
- "full_name": "test_prog$Object"
+ "full_name": "test_prog$Bool"
+ }, {
+ "full_name": "test_prog$Float"
}, {
"full_name": "test_prog$Int"
}, {
- "full_name": "test_prog$Float"
+ "full_name": "test_prog$List"
}, {
- "full_name": "test_prog$Bool"
+ "full_name": "test_prog$Object"
}, {
"full_name": "test_prog$String"
- }, {
- "full_name": "test_prog$List"
}],
"intro_mclassdefs": [{
- "full_name": "test_prog$Object"
+ "full_name": "test_prog$Bool"
+ }, {
+ "full_name": "test_prog$Float"
}, {
"full_name": "test_prog$Int"
}, {
- "full_name": "test_prog$Float"
+ "full_name": "test_prog$List"
}, {
- "full_name": "test_prog$Bool"
+ "full_name": "test_prog$Object"
}, {
"full_name": "test_prog$String"
- }, {
- "full_name": "test_prog$List"
}],
"redef_mclassdefs": [],
"imports": []
"full_name": "test_prog>rpg>"
},
"intro_mclasses": [{
- "full_name": "test_prog::Career"
+ "full_name": "test_prog::Alcoholic"
}, {
- "full_name": "test_prog::Warrior"
+ "full_name": "test_prog::Career"
}, {
"full_name": "test_prog::Magician"
}, {
- "full_name": "test_prog::Alcoholic"
+ "full_name": "test_prog::Warrior"
}],
"mclassdefs": [{
- "full_name": "test_prog$Career"
+ "full_name": "test_prog$Alcoholic"
}, {
- "full_name": "test_prog$Warrior"
+ "full_name": "test_prog$Career"
}, {
"full_name": "test_prog$Magician"
}, {
- "full_name": "test_prog$Alcoholic"
+ "full_name": "test_prog$Warrior"
}],
"intro_mclassdefs": [{
- "full_name": "test_prog$Career"
+ "full_name": "test_prog$Alcoholic"
}, {
- "full_name": "test_prog$Warrior"
+ "full_name": "test_prog$Career"
}, {
"full_name": "test_prog$Magician"
}, {
- "full_name": "test_prog$Alcoholic"
+ "full_name": "test_prog$Warrior"
}],
"redef_mclassdefs": [],
"imports": [{
"full_name": "test_prog>rpg>"
},
"intro_mclasses": [{
- "full_name": "test_prog::Weapon"
- }, {
"full_name": "test_prog::Combatable"
+ }, {
+ "full_name": "test_prog::Weapon"
}],
"mclassdefs": [{
- "full_name": "test_prog$Weapon"
+ "full_name": "test_prog::combat$Character"
}, {
"full_name": "test_prog$Combatable"
}, {
- "full_name": "test_prog::combat$Character"
- }, {
"full_name": "test_prog::combat$Dwarf"
+ }, {
+ "full_name": "test_prog$Weapon"
}],
"intro_mclassdefs": [{
- "full_name": "test_prog$Weapon"
- }, {
"full_name": "test_prog$Combatable"
+ }, {
+ "full_name": "test_prog$Weapon"
}],
"redef_mclassdefs": [{
"full_name": "test_prog::combat$Character"
"full_name": "test_prog>rpg>"
},
"intro_mclasses": [{
- "full_name": "test_prog::Race"
- }, {
- "full_name": "test_prog::Human"
- }, {
"full_name": "test_prog::Dwarf"
}, {
"full_name": "test_prog::Elf"
- }],
- "mclassdefs": [{
- "full_name": "test_prog$Race"
}, {
- "full_name": "test_prog$Human"
+ "full_name": "test_prog::Human"
}, {
+ "full_name": "test_prog::Race"
+ }],
+ "mclassdefs": [{
"full_name": "test_prog$Dwarf"
}, {
"full_name": "test_prog$Elf"
- }],
- "intro_mclassdefs": [{
- "full_name": "test_prog$Race"
}, {
"full_name": "test_prog$Human"
}, {
+ "full_name": "test_prog$Race"
+ }],
+ "intro_mclassdefs": [{
"full_name": "test_prog$Dwarf"
}, {
"full_name": "test_prog$Elf"
+ }, {
+ "full_name": "test_prog$Human"
+ }, {
+ "full_name": "test_prog$Race"
}],
"redef_mclassdefs": [],
"imports": [{
"full_name": "test_prog>"
},
"mgroups": [{
- "full_name": "test_prog>"
- }, {
"full_name": "test_prog>game>"
}, {
"full_name": "test_prog>platform>"
}, {
"full_name": "test_prog>rpg>"
+ }, {
+ "full_name": "test_prog>"
}],
"ini": {
"upstream.issues": "https://github.com/nitlang/nit/issues",
"full_name": "test_prog$Object"
},
"mpropdefs": [{
- "full_name": "test_prog$Object$init"
+ "full_name": "test_prog$Elf$Object::init"
}, {
"full_name": "test_prog$Career$Object::init"
}, {
}, {
"full_name": "test_prog$Dwarf$Object::init"
}, {
- "full_name": "test_prog$Elf$Object::init"
- }, {
"full_name": "test_prog$Character$Object::init"
+ }, {
+ "full_name": "test_prog$Object$init"
}],
"intro_mclass": {
"full_name": "test_prog::Object"
# Runs a webserver based on nitcorn that render things from model.
module nitweb
-import popcorn::pop_config
import popcorn::pop_auth
import frontend
import web
#
# * key: `github.client_id`
# * default: ``
- var github_client_id: String is lazy do return value_or_default("github.client.id", "")
+ fun github_client_id: String do return ini["github.client.id"] or else ""
# Github client secret used for Github OAuth login.
#
# * key: `github.client_secret`
# * default: ``
- var github_client_secret: String is lazy do
- return value_or_default("github.client.secret", "")
- end
+ fun github_client_secret: String do return ini["github.client.secret"] or else ""
end
redef class ToolContext
# Build the nitweb config from `toolcontext` options.
fun build_config(toolcontext: ToolContext, mainmodule: MModule): NitwebConfig do
- var config_file = toolcontext.opt_config.value
- if config_file == null then config_file = "nitweb.ini"
var config = new NitwebConfig(
- config_file,
toolcontext.modelbuilder.model,
mainmodule,
toolcontext.modelbuilder)
+ var config_file = toolcontext.opt_config.value
+ if config_file == null then config.default_config_file = "nitweb.ini"
+ config.parse_options(args)
var opt_host = toolcontext.opt_host.value
- if opt_host != null then config["app.host"] = opt_host
+ if opt_host != null then config.ini["app.host"] = opt_host
var opt_port = toolcontext.opt_port.value
- if opt_port >= 0 then config["app.port"] = opt_port.to_s
+ if opt_port >= 0 then config.ini["app.port"] = opt_port.to_s
return config
end
module api_feedback
import web_base
+import popcorn::pop_auth
redef class NitwebConfig
# MongoDB collection used to store stars.
- var stars: MongoCollection is lazy do return db.collection("stars")
+ var stars = new StarRatingRepo(db.collection("stars")) is lazy
end
redef class APIRouter
+
redef init do
super
+
+ use("/feedback/grades/most", new APIStarsMost(config))
+ use("/feedback/grades/best", new APIStarsBest(config))
+ use("/feedback/grades/worst", new APIStarsWorst(config))
+ use("/feedback/grades/users", new APIStarsUsers(config))
+
+ use("/feedback/user/stars", new APIUserStars(config))
+
use("/feedback/stars/:id", new APIStars(config))
+ use("/feedback/stars/:id/dimension/:dimension", new APIStarsDimension(config))
+ end
+end
+
+# Base handler for feedback features.
+abstract class APIFeedBack
+ super APIHandler
+
+ # Get the user logged in or null if no session
+ fun get_session_user(req: HttpRequest): nullable User do
+ var session = req.session
+ if session == null then return null
+ return session.user
+ end
+
+ # Get the login of the session user or null if no session
+ fun get_session_login(req: HttpRequest): nullable String do
+ var user = get_session_user(req)
+ if user == null then return null
+ return user.login
+ end
+end
+
+# Most rated entities
+class APIStarsMost
+ super APIFeedBack
+
+ redef fun get(req, res) do
+ res.json new JsonArray.from(config.stars.most_rated)
+ end
+end
+
+# Best rated entities
+class APIStarsBest
+ super APIFeedBack
+
+ redef fun get(req, res) do
+ res.json new JsonArray.from(config.stars.best_rated)
+ end
+end
+
+# Best rated entities
+class APIStarsWorst
+ super APIFeedBack
+
+ redef fun get(req, res) do
+ res.json new JsonArray.from(config.stars.worst_rated)
+ end
+end
+
+# Best rated entities
+class APIStarsUsers
+ super APIFeedBack
+
+ redef fun get(req, res) do
+ res.json new JsonArray.from(config.stars.users_ratings)
+ end
+end
+
+# Stars attributed to mentities by user
+class APIUserStars
+ super APIFeedBack
+
+ redef fun get(req, res) do
+ var user = get_session_user(req)
+ if user == null then return
+ res.json new JsonArray.from(user.ratings(config))
end
end
# Stars attributed to mentities
class APIStars
- super APIHandler
+ super APIFeedBack
redef fun get(req, res) do
+ var login = get_session_login(req)
var mentity = mentity_from_uri(req, res)
if mentity == null then return
- res.json mentity_ratings(mentity)
+ res.json mentity.ratings(config, login)
+ end
+end
+
+# Stars attributed to mentities by dimension
+class APIStarsDimension
+ super APIFeedBack
+
+ redef fun get(req, res) do
+ var login = get_session_login(req)
+ var mentity = mentity_from_uri(req, res)
+ if mentity == null then return
+ var dimension = req.param("dimension")
+ if dimension == null then return
+ res.json mentity.ratings_by_dimension(config, dimension, login)
end
redef fun post(req, res) do
+ var user = get_session_user(req)
+ var login = null
+ if user != null then login = user.login
+
var mentity = mentity_from_uri(req, res)
if mentity == null then return
+ var dimension = req.param("dimension")
+ if dimension == null then return
+
+ # Retrieve user previous rating
+ var previous = null
+ if user != null then
+ previous = user.find_previous_rating(config, mentity, dimension)
+ end
+
var obj = req.body.parse_json
if not obj isa JsonObject then
res.api_error(400, "Expected a JSON object")
return
end
- var val = new MEntityRating(mentity.full_name, rating, get_time)
- config.stars.insert(val.json)
-
- res.json mentity_ratings(mentity)
+ if previous != null then
+ previous.rating = rating
+ previous.timestamp = get_time
+ config.stars.save previous
+ else
+ config.stars.save new StarRating(login, mentity.full_name, dimension, rating)
+ end
+ res.json mentity.ratings_by_dimension(config, dimension, login)
end
+end
- # Get the ratings of a `mentity`
- fun mentity_ratings(mentity: MEntity): MEntityRatings do
- var ratings = new MEntityRatings(mentity)
+# Star ratings allow users to rate mentities with a 5-stars system.
+#
+# Each rating can consider only one `dimension` of the mentity.
+# Dimensions are arbitrary strings used to group ratings.
+class StarRating
+ super RepoObject
+ serialize
- var req = new JsonObject
- req["mentity"] = mentity.full_name
- var rs = config.stars.find_all(req)
- for r in rs do ratings.ratings.add new MEntityRating.from_json(r)
- return ratings
- end
-end
+ # The user login that made that rating (or null if anon)
+ var user: nullable String
-# Ratings representation for a mentity
-class MEntityRatings
- super Jsonable
+ # Rated `MEntity::full_name`
+ var mentity: String
- # MEntity rated
- var mentity: MEntity
+ # The dimension rated (arbritrary key)
+ var dimension: nullable String
- # List of ratings
- var ratings = new Array[MEntityRating]
+ # The rating (traditionally a score between 0 and 5)
+ var rating: Int is writable
- # Mean of all ratings or 0
- fun mean: Float do
- if ratings.is_empty then return 0.0
- var sum = 0.0
- for r in ratings do sum += r.rating.to_f
- var res = sum / ratings.length.to_f
- return res
+ # Timestamp when this rating was created
+ var timestamp = 0 is writable
+end
+
+redef class User
+
+ # Find a previous rating of `self` for `mentity` and `dimension`
+ fun find_previous_rating(config: NitwebConfig, mentity: MEntity, dimension: nullable String): nullable StarRating do
+ var match = new MongoMatch
+ match.eq("mentity", mentity.full_name)
+ match.eq("dimension", dimension)
+ match.eq("user", login)
+ return config.stars.find(match)
end
- # Json representation of `self`
- fun json: JsonObject do
+ # Find all ratings by `self`
+ fun ratings(config: NitwebConfig): Array[StarRating] do
+ return config.stars.find_all((new MongoMatch).eq("user", login))
+ end
+end
+
+redef class MEntity
+
+ # Get the ratings of a `dimension`
+ fun ratings_by_dimension(config: NitwebConfig, dimension: String, user: nullable String): JsonObject do
+ var match = (new MongoMatch).eq("mentity", full_name).eq("dimension", dimension)
+ var pipeline = new MongoPipeline
+ pipeline.match(match)
+ pipeline.group((new MongoGroup("mean_group")).avg("mean", "$rating"))
+
+ var res = config.stars.collection.aggregate(pipeline)
var obj = new JsonObject
- obj["mentity"] = mentity.full_name
- obj["ratings"] = new JsonArray.from(ratings)
- obj["mean"] = mean
+ obj["mean"] = if res.is_empty then 0.0 else res.first["mean"]
+ obj["ratings"] = new JsonArray.from(config.stars.find_all(match))
+
+ if user != null then
+ match["user"] = user
+ obj["user"] = config.stars.find(match)
+ end
return obj
end
- redef fun serialize_to(v) do json.serialize_to(v)
+ # Get the ratings of a `mentity`
+ fun ratings(config: NitwebConfig, user: nullable String): JsonObject do
+ var match = new JsonObject
+ match["mentity"] = full_name
+ match["ratings"] = new JsonArray.from(config.stars.find_all(match))
+ match["feature"] = ratings_by_dimension(config, "feature", user)
+ match["doc"] = ratings_by_dimension(config, "doc", user)
+ match["examples"] = ratings_by_dimension(config, "examples", user)
+ match["code"] = ratings_by_dimension(config, "code", user)
+ return match
+ end
end
-# Rating value of a MEntity
-class MEntityRating
- super Jsonable
-
- # MEntity this rating is about
- var mentity: String
-
- # Rating value (between 1 and 5)
- var rating: Int
+# StarRating Mongo Repository
+class StarRatingRepo
+ super MongoRepository[StarRating]
- # Timestamp of this rating
- var timestamp: Int
+ # Find most rated mentities
+ fun most_rated: Array[JsonObject] do
+ var pipeline = new MongoPipeline
+ pipeline.group((new MongoGroup("$mentity")).sum("count", 1))
+ pipeline.sort((new MongoMatch).eq("count", -1))
+ pipeline.limit(10)
+ return collection.aggregate(pipeline)
+ end
- # Init this rating value from a JsonObject
- init from_json(obj: JsonObject) do
- init(obj["mentity"].as(String), obj["rating"].as(Int), obj["timestamp"].as(Int))
+ # Find best rated mentities
+ fun best_rated: Array[JsonObject] do
+ var pipeline = new MongoPipeline
+ pipeline.group((new MongoGroup("$mentity")).avg("avg", "$rating"))
+ pipeline.sort((new MongoMatch).eq("avg", -1))
+ pipeline.limit(10)
+ return collection.aggregate(pipeline)
end
- # Translate this rating value to a JsonObject
- fun json: JsonObject do
- var obj = new JsonObject
- obj["mentity"] = mentity
- obj["rating"] = rating
- obj["timestamp"] = timestamp
- return obj
+ # Find worst rated mentities
+ fun worst_rated: Array[JsonObject] do
+ var pipeline = new MongoPipeline
+ pipeline.group((new MongoGroup("$mentity")).avg("avg", "$rating"))
+ pipeline.sort((new MongoMatch).eq("avg", 1))
+ pipeline.limit(10)
+ return collection.aggregate(pipeline)
end
- redef fun serialize_to(v) do json.serialize_to(v)
+ # Find worst rated mentities
+ fun users_ratings: Array[JsonObject] do
+ var pipeline = new MongoPipeline
+ pipeline.group((new MongoGroup("$user")).sum("count", 1))
+ pipeline.sort((new MongoMatch).eq("count", -1))
+ pipeline.limit(10)
+ return collection.aggregate(pipeline)
+ end
end
return mentities
end
+ # Sort mentities by lexicographic order
+ #
+ # TODO choose order from request
+ fun sort_mentities(req: HttpRequest, mentities: Array[MEntity]) : Array[MEntity] do
+ var sorted = mentities.to_a
+ var sorter = new MEntityNameSorter
+ sorter.sort(sorted)
+ return sorted
+ end
+
# Limit mentities depending on the `n` parameter.
fun limit_mentities(req: HttpRequest, mentities: Array[MEntity]): Array[MEntity] do
var n = req.int_arg("n")
redef fun get(req, res) do
var mentities = list_mentities(req)
+ mentities = sort_mentities(req, mentities)
mentities = limit_mentities(req, mentities)
res.json new JsonArray.from(mentities)
end
#
# Example: `GET /defs/core::Array`
class APIEntityDefs
- super APIHandler
+ super APIList
redef fun get(req, res) do
var mentity = mentity_from_uri(req, res)
if mentity == null then return
- var arr = new JsonArray
+ var mentities: Array[MEntity]
if mentity isa MModule then
- for mclassdef in mentity.mclassdefs do arr.add mclassdef
+ mentities = mentity.mclassdefs
else if mentity isa MClass then
- for mclassdef in mentity.mclassdefs do arr.add mclassdef
+ mentities = mentity.mclassdefs
else if mentity isa MClassDef then
- for mpropdef in mentity.mpropdefs do arr.add mpropdef
+ mentities = mentity.mpropdefs
else if mentity isa MProperty then
- for mpropdef in mentity.mpropdefs do arr.add mpropdef
+ mentities = mentity.mpropdefs
else
res.api_error(404, "No definition list for mentity `{mentity.full_name}`")
return
end
- res.json arr
+ mentities = sort_mentities(req, mentities)
+ mentities = limit_mentities(req, mentities)
+ res.json new JsonArray.from(mentities)
end
end
class NitwebConfig
super AppConfig
- redef var default_db_name = "nitweb"
+ redef fun default_db_name do return "nitweb"
# Model to use.
var model: Model