llt-review 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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);