Reviser
###Description
Reviser is a semi-automatic tool for student's projects evaluation, written in Ruby.
###Installation
Download and install the gem with the following command line.
gem install reviser
###Basic usage
To create a new workspace in the current directory, simply run the following command in a terminal:
reviser init .
Create res
Create type
Create config.yml
Create labels.yml
You see reviser has created res and type/example folders for you. Now you'll have to customize config.yml to your own needs, and add a type/your_project.yml
To perform the analysis, simply run:
reviser work
###How it works
Our tool is divided into 4 main components :
Component | Role |
---|---|
Archiver | Extracting all computing projects |
Organiser | Parsing students names and renaming directories appropriately |
Checker | Running the analysis based upon selected criteria and extensions |
Generator | Generating the analysis results in various formats |
The basic idea is that each component can receive data from any of the components run before it. It shall requests that input upon loading. The work command actually runs the above components with the appropriate input data (e.g. Generator relies on Checker results).
###Configuration
This tool was thought to be very adaptable, thus it relies on YAML configuration files.
###Global configuration Lives in config.yml.
###Project configuration Lives in type/my_project.yml.
###Labels configuration
Each criterion is associated with a label. A label is some words, describing the criterion's result. For example, a criterion which checks the existence of a Makefile could have a label like 'Existence of Makefile'.
By default, labels are generated with the name of the called method. You have the possibility to customize this label thanks to the command line tool:
reviser add makefile? 'Existence of makefile'
# method associated label
Labels are stored in your workspace, in a file called labels.yml. You can also edit them by hand if you prefer.
###Extensions Extensions are in fact Criteria we didn't want to include into reviser's core. Reviser's core aims to rely as much as possible on native Ruby APIs to ensure its portability. That's why Extensions exist: they basically are Criteria which relies on platform-spefic-features.
As of now, there are 2 extensions:
Extension | Description | Add it to your workspace extensions |
---|---|---|
Valgrind | Runs a memcheck through system call to valgrind | memleaks |
WebValidators | Validates HTML and CSS through W3C API calls (requires w3c_validators gem) | validate_web |
###Working on your own
If you have very special needs, you may need to create your own components or extensions. You'll then need to load your components at the right time, and register your extensions for them to be available.
####Custom components
We're going to show you how to create a custom generator that will generate a nice-looking HTML table using jQuery dataTables.
example/my_generator.rb
#
# This is a simple component showing how to extend Reviser
# We are going to build a custom HTML generator with jQuery :-)
#
require 'reviser'
class MyGenerator < Reviser::Component
#
# We're expecting results from Checker as data
#
def initialize data
super data
#
# We want the HTML output
#
@data.each do |project, results|
results.each do |criterion, value|
@data[project][criterion] = value.html
end
end
end
def run
#
# Get our template file
#
template = resource('html/results_template.html').read
out = '<thead><tr>'
#
# Each criterion as headings
#
@data.values.first.keys.unshift.unshift('Projet').each { |crit| out += "<th>#{crit}</th>" }
out += '</tr></thead><tbody>'
# Values for each project as rows
@data.keys.each do |proj|
out += "<tr><th>#{proj}</th>"
@data[proj].each do |k, v|
out += "<td>#{v.to_s.strip}</td>"
end
out += '</tr>'
end
out += '</tbody>'
#
# Kind of a hacky template engine
# We replace placeholders with actual values
#
template.sub! '[DATA]', out
template.sub! '[MAINCSS_PATH]', resource('css/main.css').to_path
File.open('my_results.html', 'w') { |f| f.write template }
end
end
example/res/my_generator/html/results_template.html
<!DOCTYPE html>
<html>
<head>
<meta charset= "UTF-8">
<link rel="stylesheet" type="text/css" href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="http://cdn.datatables.net/plug-ins/f2c75b7247b/integration/bootstrap/3/dataTables.bootstrap.css">
<link rel="stylesheet" type="text/css" href="[MAINCSS_PATH]">
<script type="text/javascript" src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="http://cdn.datatables.net/1.10.5/js/jquery.dataTables.min.js"></script>
<script type="text/javascript" src="http://cdn.datatables.net/plug-ins/f2c75b7247b/integration/bootstrap/3/dataTables.bootstrap.js"></script>
<title>My results</title>
<script type="text/javascript">
$(document).ready(function() {
$('#results').dataTable({"dom":' <"search"fl><"top">rt<"bottom"ip><"clear">'});
});
</script>
</head>
<body>
<table id="results">
[DATA]
</table>
<script type="text/javascript">
$('#results').removeClass('display').addClass('table table-striped table-bordered');
</script>
</body>
</html>
####Custom extensions
Now let's create a custom criterion ! This one is very simple : it will calculate project's size thanks to filesize gem.
Creating an extension is as simple as creating a module. In fact, when you register that module as an extension, its methods become available for you to add in extensions configuration key.
example/my_extension.rb
require 'find'
require 'reviser'
#
# A custom criteria for reviser
#
module MyExtension
#
# This helper has the 'sources' methods
# that allow you to retrieve all sources
# files (files matching language extension)
# as well as the 'manufacture' method,
# needed to adapt results to out format
#
include Reviser::Helpers::Project
#
# Keep in mind that this method will be run
# in each project's directory !
# (that's why we use FileUtils.pwd)
#
def project_size
#
# That's the way we require gems without worrying
# of them being installed or not !
# require_gem is in global scope, and will raise an
# exception if the given gem is not installed.
# It will include it otherwise
#
unless defined? Filesize
require_gem 'filesize'
end
size_in_bytes = size(FileUtils.pwd)
results = Filesize.from("#{size_in_bytes} B").pretty
#
# The manufacture method excepts
# a block which must describe the result contents
# for EACH format.
# You can also return raw data, then it'll be as it is
# for all formats.
#
manufacture do |format|
format.html { '<span style="font-weight:bold;">' + results + '</span>' }
format.csv { results }
format.xls { results }
end
end
private
#
# Returns the size of all the given
# files (even if there are also dirs)
# in bytes
#
def size(dir)
bytes = 0
Find.find(*Dir["#{dir}/**/*"]) { |f| bytes += File.stat(f).size }
bytes.to_f
end
end
Putting it together
example/config.yml
extensions:
- project_size
example/my_app.rb
This file shows how to plug your custom component into reviser's workflow as well as how to make your custom extension available.
require 'reviser'
require_relative 'my_extension'
require_relative 'my_generator'
module MyApp
include Reviser
def self.run config_file = 'config.yml'
#
# Setup reviser
#
Reviser::setup config_file
#
# You can now use MyExtension's methods for analysis
#
Reviser::register :extension => 'MyExtension'
#
# You can load any built-in component (archiver, organiser, checker, generator)
# But be aware that they have to be ran in this order, and that
# organiser takes input from archiver, checker from organiser and generator from checker
# If you don't respect that, nothing will work.
# But you can run your component at any step, this won't break the process.
#
Reviser::load :component => 'archiver'
Reviser::load :component => 'organiser', :input_from => 'archiver'
Reviser::load :component => 'checker', :input_from => 'organiser'
#
# We run our custom generator instead :-)
#
# With :local => true, we tell reviser not to look for our component
# in its core ones but to let us include it ourselves instead
#
Reviser::load :component => 'my_generator', :input_from => 'checker', :local => true
# Reviser::load :component => 'generator', :input_from => 'checker'
#
# Run reviser
#
Reviser::run
end
end
example/main.rb
require_relative 'my_app'
#
# You can then run your app (don't forget you still need to be in a reviser workspace,
# so type/ and res/ folders must exist, as well as config.yml)
#
MyApp::run
Team
Other stuff
Question | Answer |
---|---|
Requires | Ruby 1.9.3 or later |