llt-review 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c67647d0b4ba29bff3feb4066ed2d11eb2253a41
4
- data.tar.gz: 6f8ba9c45e85319859765ce378ead8a654a2f12a
3
+ metadata.gz: 91ff18f1e72915936a2069917fa843b701ee7df8
4
+ data.tar.gz: f4398109dc7d16bdfed7980a6dba2359c7350c0a
5
5
  SHA512:
6
- metadata.gz: 6bf66bd60ab8558ea51be1fa765c87540cbd419e993cdfe1ec4ce188284c19685c739f05f88115d4cb6b93bddcbdca91a71c19be378fa91c66653dbb6bc3427b
7
- data.tar.gz: 9bba65d16cc077da638427d74aa31d84e258aa14f2456757903ea801cfd08e7b91999bfeee6526f503831d7c17e39342b65f2cf1c5bd8f9feac7389f4ed8082b
6
+ metadata.gz: 3e5087b17bef29c42939a587f667636f848773a6a5e0902936753413fafdeb51901327e222fd31eda844f9233555a69762adf236c82bf68c5e4658541569ccfa
7
+ data.tar.gz: 7eef4e5e71816b0fd7ef3d10e436c84f649c85e1d6ac23baedf9414c99b2b9f74640deac6807dca701e68bf246d65283f84cd25e72f5be4475de832ea98ae693
data/.gitignore CHANGED
@@ -15,3 +15,4 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
+ .sass-cache
data/config.ru CHANGED
@@ -1,2 +1,8 @@
1
+ require 'haml'
2
+ require 'sass/plugin/rack'
1
3
  require 'llt/review/api'
4
+
5
+ Sass::Plugin.options[:style] = :compressed
6
+ use Sass::Plugin::Rack
7
+
2
8
  run Api
@@ -36,7 +36,7 @@ module LLT
36
36
  def set_languages(attrs)
37
37
  hsh = Hash[attrs]
38
38
  lang = hsh['xml:lang']
39
- hsh['lnum'] == 'l1' ? @lang1 = lang : @lang2 = lang
39
+ hsh['lnum'] == 'L1' ? @lang1 = lang : @lang2 = lang
40
40
  end
41
41
  end
42
42
  end
@@ -0,0 +1,47 @@
1
+ module LLT
2
+ module Review::Api
3
+ module Helpers
4
+ def origin(el)
5
+ "Publication ##{extracted_id(el.id)} by #{el.sentences.annotators}"
6
+ end
7
+
8
+ def combined_extracted_id(comp)
9
+ ids = [comp.gold, comp.reviewable].map { |el| extracted_id(el.id)}.join('-')
10
+ "comp#{ids}"
11
+ end
12
+
13
+ def extracted_id(id)
14
+ last = id.split('/').last
15
+ /(.*?)(\.([\w]*?))?$/.match(last)[1]
16
+ end
17
+
18
+ def arethusa(rev, gold, lang, chunk = nil, word = nil)
19
+ path = "http://sosol.perseids.org/tools/arethusa/app/#/perseids_review_#{lang}_aldt"
20
+ path << "?doc=#{rev}&gold=#{gold}"
21
+ if chunk || word
22
+ path << "&chunk=#{chunk}" if chunk
23
+ path << "&w=#{word}" if word
24
+ end
25
+ path
26
+ end
27
+
28
+ def to_tooltip(cat, v)
29
+ %{#{cat}: <span class="success">#{v.original}</span> -> <span class="error">#{v.new}</span>}
30
+ end
31
+
32
+ def extract_heads(diff, s_id)
33
+ if heads = diff[:head]
34
+ [to_id(s_id, heads.original), to_id(s_id, heads.new)]
35
+ end
36
+ end
37
+
38
+ def to_id(s_id, w_id)
39
+ "#{s_id}-#{w_id}"
40
+ end
41
+
42
+ def to_percent(total, part)
43
+ ((part.to_f / total) * 100).round(2)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -1,29 +1,34 @@
1
1
  require 'sinatra/base'
2
2
  require 'sinatra/respond_with'
3
3
  require 'llt/review'
4
+ require 'llt/review/api/helpers'
4
5
 
5
6
  class Api < Sinatra::Base
6
7
  register Sinatra::RespondWith
7
8
 
8
- get '/:type/diff' do
9
- gold = Array(params[:gold])
10
- rev = Array(params[:reviewable])
9
+ set :root, File.expand_path('../../../..', __FILE__)
11
10
 
12
- comp_param = params[:compare]
13
- comparables = comp_param ? Array(comp_param).map(&:to_sym) : nil
14
11
 
15
- klass = params[:type]
16
- # return an error if klass is neither treebank nor Alignment
12
+ helpers LLT::Review::Api::Helpers
17
13
 
18
- diff = LLT::Review.const_get(klass.capitalize).new
19
- puts comparables
20
- diff.diff(gold, rev, comparables)
14
+ get '/:type/diff' do
15
+ process_params(params)
16
+ diff = process_diff(params)
21
17
 
22
18
  respond_to do |f|
23
19
  f.xml { diff.to_xml }
24
20
  end
25
21
  end
26
22
 
23
+ get '/:type/diff/:view' do
24
+ process_params(params)
25
+ diff = process_diff(params)
26
+
27
+ if params[:view] == 'html'
28
+ haml :index, locals: { diff: diff }
29
+ end
30
+ end
31
+
27
32
  get '/:type/report' do
28
33
  uris = Array(params[:uri])
29
34
  klass = params[:type]
@@ -34,4 +39,38 @@ class Api < Sinatra::Base
34
39
  f.xml { reporter.to_xml(:report)}
35
40
  end
36
41
  end
42
+
43
+ def process_params(params)
44
+ if backend = params[:backend]
45
+ p = case backend
46
+ when 'perseids' then 'sosol.perseids.org/sosol'
47
+ when 'perseids-dev' then 'dev.alpheios.net:3000'
48
+ end
49
+
50
+ expand_perseids_urls(params, :gold, p)
51
+ expand_perseids_urls(params, :reviewable, p)
52
+ end
53
+ end
54
+
55
+ def process_diff(params)
56
+ gold = Array(params[:gold])
57
+ rev = Array(params[:reviewable])
58
+
59
+ comp_param = params[:compare]
60
+ comparables = comp_param ? Array(comp_param).map(&:to_sym) : nil
61
+
62
+ klass = params[:type]
63
+ # return an error if klass is neither treebank nor Alignment
64
+
65
+ diff = LLT::Review.const_get(klass.capitalize).new
66
+ diff.diff(gold, rev, comparables)
67
+ diff
68
+ end
69
+
70
+ def expand_perseids_urls(params, key, sosol_path)
71
+ t = Array(params[key])
72
+ params[key] = t.map do |publication_id|
73
+ "http://#{sosol_path}/dmm_api/item/TreebankCite/#{publication_id}"
74
+ end
75
+ end
37
76
  end
@@ -1,12 +1,18 @@
1
1
  module LLT
2
2
  class Review::Common
3
3
  module Golden
4
- attr_reader :sentences
4
+ attr_accessor :sentences
5
5
 
6
6
  # Check Comparison#report to learn more
7
7
  def clone
8
8
  cloned = super
9
+ # need to go to some lengths here, as Parsing::Result objects,
10
+ # which hide behind @sentences, have important inst vars of
11
+ # their own now and are not simply HashContainables
12
+ parse_result = @sentences.clone;
9
13
  cloned.replace_with_clone(:sentences, :report)
14
+ parse_result.container.merge!(cloned.sentences)
15
+ cloned.sentences = parse_result
10
16
  cloned
11
17
  end
12
18
  end
@@ -0,0 +1,15 @@
1
+ module LLT
2
+ module Review::Helpers::Parsing::Helper
3
+ class Annotator
4
+ attr_accessor :short, :name, :address, :uri
5
+
6
+ def complete?
7
+ @short && @name && @address && @uri
8
+ end
9
+
10
+ def name_and_short_to_s
11
+ "#{@name} (#{@short})"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,25 @@
1
+ module LLT
2
+ module Review::Helpers::Parsing::Helper
3
+ class Annotators
4
+ def initialize
5
+ @annotators = []
6
+ end
7
+
8
+ def add(annotator)
9
+ @annotators << annotator
10
+ end
11
+
12
+ def to_s
13
+ meth = :name_and_short_to_s
14
+ case @annotators.length
15
+ when 0 then "unknown annotators"
16
+ when 1 then @annotators.first.send(meth)
17
+ when 2 then @annotators.map { |a| a.send(meth) }.join(' and ')
18
+ else
19
+ with_punct = @annotators[0..-2].map { |a| a.send(meth) }.join(', ')
20
+ "#{with_punct} and #{@annotators.last.send(meth)}"
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -1,6 +1,8 @@
1
1
  module LLT
2
2
  module Review::Helpers::Parsing::Helper
3
3
  require 'llt/review/helpers/parsing/helper/for_nokogiri'
4
+ require 'llt/review/helpers/parsing/helper/annotators'
5
+ require 'llt/review/helpers/parsing/helper/annotator'
4
6
 
5
7
  def initialize
6
8
  @result = Review::Helpers::Parsing::Result.new
@@ -22,9 +24,42 @@ module LLT
22
24
  @sentence.add(@word)
23
25
  end
24
26
 
27
+ def register_format(format)
28
+ @result.format = format
29
+ end
30
+
31
+ def register_language(language)
32
+ @result.lang = language
33
+ end
34
+
25
35
  def namespace
26
36
  # has should be implemented by classes that use this module
27
37
  self.class
28
38
  end
39
+
40
+ def annotator
41
+ @annotator ||= Annotator.new
42
+ end
43
+
44
+ def add_complete_annotator
45
+ if annotator.complete?
46
+ @result.annotators.add(annotator)
47
+ @annotator = nil
48
+ end
49
+ end
50
+
51
+ def set_annotator_variable(attr, val)
52
+ instance_variable_set("@in_#{attr}", val);
53
+ end
54
+
55
+ def parse_annotator_values(str)
56
+ params = [:short, :name, :address, :uri]
57
+ params.each do |param|
58
+ if instance_variable_get("@in_#{param}")
59
+ annotator.send("#{param}=", str)
60
+ add_complete_annotator
61
+ end
62
+ end
63
+ end
29
64
  end
30
65
  end
@@ -1,6 +1,12 @@
1
1
  module LLT
2
2
  module Review::Helpers::Parsing
3
3
  class Result
4
+ attr_accessor :format, :lang
5
+
6
+ def annotators
7
+ @annotators ||= Helper::Annotators.new
8
+ end
9
+
4
10
  include Core::Structures::HashContainable
5
11
  end
6
12
  end
@@ -16,6 +16,10 @@ module LLT
16
16
  each { |_, el| el.init_diff }
17
17
  end
18
18
 
19
+ def percentage(category = :right)
20
+ ((send(category).to_f / @total) * 100).round(2)
21
+ end
22
+
19
23
  def add(element)
20
24
  if el = @container[element.id]
21
25
  el.add_total(element)
@@ -16,6 +16,28 @@ module LLT
16
16
  case name
17
17
  when 'word' then register_word(attrs)
18
18
  when 'sentence' then register_sentence(first_val(attrs))
19
+ when 'treebank' then register_treebank_attrs(attrs)
20
+ when 'annotator' then @in_annotator = true
21
+ end
22
+
23
+ if @in_annotator
24
+ set_annotator_variable(name, true)
25
+ end
26
+ end
27
+
28
+ def end_element(name, attrs = [])
29
+ if name == 'annotator'
30
+ @in_annotator = false
31
+ end
32
+
33
+ if @in_annotator
34
+ set_annotator_variable(name, false)
35
+ end
36
+ end
37
+
38
+ def characters(string)
39
+ if @in_annotator
40
+ parse_annotator_values(string)
19
41
  end
20
42
  end
21
43
 
@@ -25,6 +47,12 @@ module LLT
25
47
  super(attrs.shift.last) # need to shift, we don't want the id in the next step
26
48
  attrs.each { |k, v| @word.send("#{k}=", v) }
27
49
  end
50
+
51
+ def register_treebank_attrs(attrs)
52
+ hsh = Hash[attrs]
53
+ register_language(hsh['xml:lang'])
54
+ register_format(hsh['format'])
55
+ end
28
56
  end
29
57
  end
30
58
  end
@@ -15,6 +15,12 @@ module LLT
15
15
  case name
16
16
  when :word then @in_word = true
17
17
  when :sentence then @in_sentence = true
18
+ when :annotator then @in_annotator = true
19
+ when :treebank then @in_treebank = true
20
+ end
21
+
22
+ if @in_annotator
23
+ set_annotator_variable(name, true)
18
24
  end
19
25
  end
20
26
 
@@ -22,6 +28,11 @@ module LLT
22
28
  case name
23
29
  when :word then @in_word = false
24
30
  when :sentence then @in_sentence = false
31
+ when :annotator then @in_annotator = false
32
+ end
33
+
34
+ if @in_annotator
35
+ set_annotator_variable(name, false)
25
36
  end
26
37
  end
27
38
 
@@ -35,6 +46,15 @@ module LLT
35
46
  end
36
47
  when @in_sentence
37
48
  register_sentence(value) if name == :id
49
+ when @in_treebank
50
+ register_language(value) if name == :"xml:lang"
51
+ register_format(value) if name == :format
52
+ end
53
+ end
54
+
55
+ def text(value)
56
+ if @in_annotator
57
+ parse_annotator_values(value)
38
58
  end
39
59
  end
40
60
  end
@@ -16,13 +16,11 @@ module LLT
16
16
  def report
17
17
  @report ||= begin
18
18
  # Questionable what the total numbers of datapoints should be.
19
- # Count empty points as well?
20
19
  data = Report::Datapoints.new(@postag.size)
21
20
  add_datapoints_container(data)
22
21
  data.each_with_index do |(_, container), i|
23
22
  rtr = container.reports_to_request
24
23
  val = @postag[i]
25
- next unless val && val != '-'
26
24
  container.add(Report::Postag::Datapoint.new(rtr, val))
27
25
  container.increment
28
26
  end
@@ -1,5 +1,5 @@
1
1
  module LLT
2
2
  class Review
3
- VERSION = "0.0.1"
3
+ VERSION = "0.0.2"
4
4
  end
5
5
  end
data/llt-review.gemspec CHANGED
@@ -20,6 +20,9 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_development_dependency "bundler", "~> 1.5"
22
22
  spec.add_development_dependency "rake"
23
- spec.add_development_dependency "rspec"
23
+ spec.add_development_dependency "rspec", "2.14"
24
24
  spec.add_development_dependency "simplecov", "~> 0.7"
25
+
26
+ spec.add_dependency 'sass'
27
+ spec.add_dependency 'haml'
25
28
  end
@@ -0,0 +1,91 @@
1
+ $(document).ready(function() {
2
+
3
+ function hsv2rgb(h, s, v) {
4
+ }
5
+
6
+ function percentToColor(percent) {
7
+ var h = Math.floor((100 - percent) * 120/ 100);
8
+ var s = 1, v = 1;
9
+
10
+ var rgb, i, data = [];
11
+ h = h / 60;
12
+ i = Math.floor(h);
13
+ data = [v*(1-s), v*(1-s*(h-i)), v*(1-s*(1-(h-i)))];
14
+ switch(i) {
15
+ case 0:
16
+ rgb = [v, data[2], data[0]]; break;
17
+ case 1:
18
+ rgb = [data[1], v, data[0]]; break;
19
+ case 2:
20
+ rgb = [data[0], v, data[2]]; break;
21
+ case 3:
22
+ rgb = [data[0], data[1], v]; break;
23
+ case 4:
24
+ rgb = [data[2], data[0], v]; break;
25
+ default:
26
+ rgb = [v, data[0], data[1]]; break;
27
+ }
28
+
29
+ return '#' + rgb.map(function(x){
30
+ return ("0" + Math.round(x*255).toString(16)).slice(-2);
31
+ }).join('');
32
+ }
33
+
34
+
35
+ function addTokenTooltips() {
36
+ $('.token.tooltip').tooltipsy({
37
+ content: function($el) { return $el.attr('tooltip'); },
38
+ delay: 0
39
+ });
40
+
41
+ $('.token.head-error').each(function() {
42
+ var el = $(this);
43
+ el.hover(function() {
44
+ $('#' + el.attr('hr')).toggleClass('success-bg');
45
+ $('#' + el.attr('hw')).toggleClass('error-bg');
46
+ });
47
+ });
48
+ }
49
+
50
+ function addWordsDiffBindings() {
51
+ var sel = '.word-diff-table';
52
+ $(sel).hide();
53
+ $('.word-diff-container').click(function() {
54
+ $(this).find(sel).toggle(300);
55
+ });
56
+ }
57
+
58
+ function addPercentageColors() {
59
+ $('.percentage').each(function() {
60
+ var el = $(this);
61
+ var percent = el.attr('percentage');
62
+ var color = percentToColor(100 - percent);
63
+ el.css('color', color);
64
+ });
65
+ }
66
+
67
+ function addCategoryToggler() {
68
+ $('.toggler').each(function() {
69
+ var el = $(this);
70
+ var target = el.siblings('#' + el.attr('toggler'));
71
+ el.click(function() { target.toggle(300); });
72
+ target.hide();
73
+ });
74
+ }
75
+
76
+ function addReportToggler() {
77
+ $('.comparison_toggle').each(function() {
78
+ var el = $(this);
79
+ var target = $('#' + el.attr('c_id'));
80
+ el.click(function() { target.toggle(300); });
81
+ el.addClass('clickable');
82
+ target.hide();
83
+ });
84
+ }
85
+
86
+ addWordsDiffBindings();
87
+ addTokenTooltips();
88
+ addPercentageColors();
89
+ addCategoryToggler();
90
+ addReportToggler();
91
+ });
@@ -0,0 +1,20 @@
1
+ /* tooltipsy by Brian Cray
2
+ * Lincensed under GPL2 - http://www.gnu.org/licenses/gpl-2.0.html
3
+ * Option quick reference:
4
+ * - alignTo: "element" or "cursor" (Defaults to "element")
5
+ * - offset: Tooltipsy distance from element or mouse cursor, dependent on alignTo setting. Set as array [x, y] (Defaults to [0, -1])
6
+ * - content: HTML or text content of tooltip. Defaults to "" (empty string), which pulls content from target element's title attribute
7
+ * - show: function(event, tooltip) to show the tooltip. Defaults to a show(100) effect
8
+ * - hide: function(event, tooltip) to hide the tooltip. Defaults to a fadeOut(100) effect
9
+ * - delay: A delay in milliseconds before showing a tooltip. Set to 0 for no delay. Defaults to 200
10
+ * - css: object containing CSS properties and values. Defaults to {} to use stylesheet for styles
11
+ * - className: DOM class for styling tooltips with CSS. Defaults to "tooltipsy"
12
+ * - showEvent: Set a custom event to bind the show function. Defaults to mouseenter
13
+ * - hideEvent: Set a custom event to bind the show function. Defaults to mouseleave
14
+ * Method quick reference:
15
+ * - $('element').data('tooltipsy').show(): Force the tooltip to show
16
+ * - $('element').data('tooltipsy').hide(): Force the tooltip to hide
17
+ * - $('element').data('tooltipsy').destroy(): Remove tooltip from DOM
18
+ * More information visit http://tooltipsy.com/
19
+ */
20
+ ;(function(a){a.tooltipsy=function(c,b){this.options=b;this.$el=a(c);this.title=this.$el.attr("title")||"";this.$el.attr("title","");this.random=parseInt(Math.random()*10000);this.ready=false;this.shown=false;this.width=0;this.height=0;this.delaytimer=null;this.$el.data("tooltipsy",this);this.init()};a.tooltipsy.prototype={init:function(){var e=this,d,b=e.$el,c=b[0];e.settings=d=a.extend({},e.defaults,e.options);d.delay=+d.delay;if(typeof d.content==="function"){e.readify()}if(d.showEvent===d.hideEvent&&d.showEvent==="click"){b.toggle(function(f){if(d.showEvent==="click"&&c.tagName=="A"){f.preventDefault()}if(d.delay>0){e.delaytimer=window.setTimeout(function(){e.show(f)},d.delay)}else{e.show(f)}},function(f){if(d.showEvent==="click"&&c.tagName=="A"){f.preventDefault()}window.clearTimeout(e.delaytimer);e.delaytimer=null;e.hide(f)})}else{b.bind(d.showEvent,function(f){if(d.showEvent==="click"&&c.tagName=="A"){f.preventDefault()}e.delaytimer=window.setTimeout(function(){e.show(f)},d.delay||0)}).bind(d.hideEvent,function(f){if(d.showEvent==="click"&&c.tagName=="A"){f.preventDefault()}window.clearTimeout(e.delaytimer);e.delaytimer=null;e.hide(f)})}},show:function(i){if(this.ready===false){this.readify()}var b=this,f=b.settings,h=b.$tipsy,k=b.$el,d=k[0],g=b.offset(d);if(b.shown===false){if((function(m){var l=0,e;for(e in m){if(m.hasOwnProperty(e)){l++}}return l})(f.css)>0){b.$tip.css(f.css)}b.width=h.outerWidth();b.height=h.outerHeight()}if(f.alignTo==="cursor"&&i){var j=[i.clientX+f.offset[0],i.clientY+f.offset[1]];if(j[0]+b.width>a(window).width()){var c={top:j[1]+"px",right:j[0]+"px",left:"auto"}}else{var c={top:j[1]+"px",left:j[0]+"px",right:"auto"}}}else{var j=[(function(){if(f.offset[0]<0){return g.left-Math.abs(f.offset[0])-b.width}else{if(f.offset[0]===0){return g.left-((b.width-k.outerWidth())/2)}else{return g.left+k.outerWidth()+f.offset[0]}}})(),(function(){if(f.offset[1]<0){return g.top-Math.abs(f.offset[1])-b.height}else{if(f.offset[1]===0){return g.top-((b.height-b.$el.outerHeight())/2)}else{return g.top+b.$el.outerHeight()+f.offset[1]}}})()]}h.css({top:j[1]+"px",left:j[0]+"px"});b.settings.show(i,h.stop(true,true))},hide:function(c){var b=this;if(b.ready===false){return}if(c&&c.relatedTarget===b.$tip[0]){b.$tip.bind("mouseleave",function(d){if(d.relatedTarget===b.$el[0]){return}b.settings.hide(d,b.$tipsy.stop(true,true))});return}b.settings.hide(c,b.$tipsy.stop(true,true))},readify:function(){this.ready=true;this.$tipsy=a('<div id="tooltipsy'+this.random+'" style="position:fixed;z-index:2147483647;display:none">').appendTo("body");this.$tip=a('<div class="'+this.settings.className+'">').appendTo(this.$tipsy);this.$tip.data("rootel",this.$el);var c=this.$el;var b=this.$tip;this.$tip.html(this.settings.content!=""?(typeof this.settings.content=="string"?this.settings.content:this.settings.content(c,b)):this.title)},offset:function(b){return this.$el[0].getBoundingClientRect()},destroy:function(){if(this.$tipsy){this.$tipsy.remove();a.removeData(this.$el,"tooltipsy")}},defaults:{alignTo:"element",offset:[0,-1],content:"",show:function(c,b){b.fadeIn(100)},hide:function(c,b){b.fadeOut(100)},css:{},className:"tooltipsy",delay:200,showEvent:"mouseenter",hideEvent:"mouseleave"}};a.fn.tooltipsy=function(b){return this.each(function(){new a.tooltipsy(this,b)})}})(jQuery);