llt-review 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +8 -0
  5. data/Gemfile +14 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +35 -0
  8. data/Rakefile +6 -0
  9. data/config.ru +2 -0
  10. data/lib/llt/review/alignment/comparison.rb +6 -0
  11. data/lib/llt/review/alignment/data.rb +7 -0
  12. data/lib/llt/review/alignment/difference/nrefs.rb +29 -0
  13. data/lib/llt/review/alignment/difference/sentence.rb +6 -0
  14. data/lib/llt/review/alignment/difference/translation.rb +27 -0
  15. data/lib/llt/review/alignment/difference/word.rb +27 -0
  16. data/lib/llt/review/alignment/difference.rb +11 -0
  17. data/lib/llt/review/alignment/gold.rb +9 -0
  18. data/lib/llt/review/alignment/parser/helper.rb +43 -0
  19. data/lib/llt/review/alignment/parser/nokogiri_handler.rb +44 -0
  20. data/lib/llt/review/alignment/parser/ox_handler.rb +68 -0
  21. data/lib/llt/review/alignment/parser.rb +13 -0
  22. data/lib/llt/review/alignment/report/generic.rb +10 -0
  23. data/lib/llt/review/alignment/report/translation.rb +7 -0
  24. data/lib/llt/review/alignment/report/word.rb +7 -0
  25. data/lib/llt/review/alignment/report.rb +15 -0
  26. data/lib/llt/review/alignment/reviewable.rb +6 -0
  27. data/lib/llt/review/alignment/sentence.rb +18 -0
  28. data/lib/llt/review/alignment/translation.rb +13 -0
  29. data/lib/llt/review/alignment/word.rb +38 -0
  30. data/lib/llt/review/alignment.rb +23 -0
  31. data/lib/llt/review/api.rb +37 -0
  32. data/lib/llt/review/common/comparison.rb +91 -0
  33. data/lib/llt/review/common/difference/sentence.rb +31 -0
  34. data/lib/llt/review/common/difference/word.rb +22 -0
  35. data/lib/llt/review/common/difference.rb +9 -0
  36. data/lib/llt/review/common/golden.rb +14 -0
  37. data/lib/llt/review/common/report/generic.rb +32 -0
  38. data/lib/llt/review/common/report.rb +66 -0
  39. data/lib/llt/review/common/reviewable.rb +34 -0
  40. data/lib/llt/review/common/sentence.rb +41 -0
  41. data/lib/llt/review/common.rb +12 -0
  42. data/lib/llt/review/helpers/diff_reporter.rb +45 -0
  43. data/lib/llt/review/helpers/parsing/helper/for_nokogiri.rb +9 -0
  44. data/lib/llt/review/helpers/parsing/helper.rb +30 -0
  45. data/lib/llt/review/helpers/parsing/result.rb +7 -0
  46. data/lib/llt/review/helpers/parsing.rb +29 -0
  47. data/lib/llt/review/helpers/reportable.rb +81 -0
  48. data/lib/llt/review/helpers.rb +10 -0
  49. data/lib/llt/review/treebank/comparison.rb +6 -0
  50. data/lib/llt/review/treebank/difference/attribute.rb +11 -0
  51. data/lib/llt/review/treebank/difference/datapoint.rb +28 -0
  52. data/lib/llt/review/treebank/difference/generic.rb +32 -0
  53. data/lib/llt/review/treebank/difference/head.rb +14 -0
  54. data/lib/llt/review/treebank/difference/lemma.rb +9 -0
  55. data/lib/llt/review/treebank/difference/postag.rb +37 -0
  56. data/lib/llt/review/treebank/difference/relation.rb +11 -0
  57. data/lib/llt/review/treebank/difference/sentence.rb +6 -0
  58. data/lib/llt/review/treebank/difference/word.rb +8 -0
  59. data/lib/llt/review/treebank/difference.rb +15 -0
  60. data/lib/llt/review/treebank/gold.rb +8 -0
  61. data/lib/llt/review/treebank/parser/helper.rb +9 -0
  62. data/lib/llt/review/treebank/parser/nokogiri_handler.rb +30 -0
  63. data/lib/llt/review/treebank/parser/ox_handler.rb +42 -0
  64. data/lib/llt/review/treebank/parser.rb +13 -0
  65. data/lib/llt/review/treebank/postag.rb +65 -0
  66. data/lib/llt/review/treebank/report/datapoints.rb +12 -0
  67. data/lib/llt/review/treebank/report/generic.rb +10 -0
  68. data/lib/llt/review/treebank/report/lemma.rb +8 -0
  69. data/lib/llt/review/treebank/report/postag/datapoint.rb +16 -0
  70. data/lib/llt/review/treebank/report/postag.rb +7 -0
  71. data/lib/llt/review/treebank/report/postags.rb +27 -0
  72. data/lib/llt/review/treebank/report/relation.rb +7 -0
  73. data/lib/llt/review/treebank/report.rb +19 -0
  74. data/lib/llt/review/treebank/reviewable.rb +6 -0
  75. data/lib/llt/review/treebank/sentence.rb +25 -0
  76. data/lib/llt/review/treebank/word.rb +53 -0
  77. data/lib/llt/review/treebank.rb +22 -0
  78. data/lib/llt/review/version.rb +5 -0
  79. data/lib/llt/review.rb +118 -0
  80. data/llt-review.gemspec +25 -0
  81. data/spec/lib/llt/review/alignment/parser_spec.rb +72 -0
  82. data/spec/lib/llt/review/alignment_spec.rb +242 -0
  83. data/spec/lib/llt/review/helpers/reportable_spec.rb +26 -0
  84. data/spec/lib/llt/review/treebank/parser_spec.rb +21 -0
  85. data/spec/lib/llt/review/treebank/postag_spec.rb +22 -0
  86. data/spec/lib/llt/review/treebank_spec.rb +222 -0
  87. data/spec/lib/llt/review_spec.rb +7 -0
  88. data/spec/spec_helper.rb +22 -0
  89. metadata +195 -0
@@ -0,0 +1,37 @@
1
+ module LLT
2
+ module Review::Treebank::Difference
3
+ class Postag < Generic
4
+ def initialize(tag, original, new)
5
+ super
6
+ compute_detailed_differences
7
+ end
8
+
9
+ def diff_id
10
+ @diff_id ||= "#{id}:#{map { |_, v| v.diff_id }.join('::')}"
11
+ end
12
+
13
+ private
14
+
15
+ # copied over right now from Postag until we figure out how to solve this
16
+ # more globally
17
+
18
+ POSTAG_SCHEMA = %i{
19
+ part_of_speech person number tense
20
+ mood voice gender case degree
21
+ }
22
+
23
+ def compute_detailed_differences
24
+ @original.each_char.with_index do |a, i|
25
+ b = @new[i]
26
+ add(Datapoint.new(POSTAG_SCHEMA[i], a, b)) unless a == b
27
+ end
28
+ end
29
+
30
+ def write_to_report(report, unique)
31
+ postags = report[:postags]
32
+ postags.add_wrong(unique)
33
+ postags[item.to_s].add_wrong(unique)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,11 @@
1
+ module LLT
2
+ module Review::Treebank::Difference
3
+ class Relation < Attribute
4
+ def report_location
5
+ :relations
6
+ end
7
+ end
8
+ end
9
+ end
10
+
11
+
@@ -0,0 +1,6 @@
1
+ module LLT
2
+ module Review::Treebank::Difference
3
+ class Sentence < Review::Common::Difference::Sentence
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,8 @@
1
+ module LLT
2
+ module Review::Treebank::Difference
3
+ class Word < Review::Common::Difference::Word
4
+ attr_reader :lemma, :head, :relation, :postag
5
+ end
6
+ end
7
+ end
8
+
@@ -0,0 +1,15 @@
1
+ module LLT
2
+ class Review::Treebank
3
+ module Difference
4
+ require 'llt/review/treebank/difference/sentence'
5
+ require 'llt/review/treebank/difference/word'
6
+ require 'llt/review/treebank/difference/generic'
7
+ require 'llt/review/treebank/difference/attribute'
8
+ require 'llt/review/treebank/difference/postag'
9
+ require 'llt/review/treebank/difference/datapoint'
10
+ require 'llt/review/treebank/difference/head'
11
+ require 'llt/review/treebank/difference/lemma'
12
+ require 'llt/review/treebank/difference/relation'
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,8 @@
1
+ module LLT
2
+ class Review::Treebank
3
+ class Gold < Report
4
+ include Review::Common::Golden
5
+ end
6
+ end
7
+ end
8
+
@@ -0,0 +1,9 @@
1
+ module LLT
2
+ class Review::Treebank::Parser
3
+ module Helper
4
+ def namespace
5
+ Review::Treebank
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,30 @@
1
+ require 'nokogiri'
2
+
3
+ module LLT
4
+ class Review::Treebank::Parser
5
+ class NokogiriHandler < Nokogiri::XML::SAX::Document
6
+
7
+ include Review::Helpers::Parsing::Helper
8
+ include Review::Helpers::Parsing::Helper::ForNokogiri
9
+ include Helper
10
+
11
+ def parse(data)
12
+ Nokogiri::XML::SAX::Parser.new(self).parse(data)
13
+ end
14
+
15
+ def start_element(name, attrs = [])
16
+ case name
17
+ when 'word' then register_word(attrs)
18
+ when 'sentence' then register_sentence(first_val(attrs))
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def register_word(attrs)
25
+ super(attrs.shift.last) # need to shift, we don't want the id in the next step
26
+ attrs.each { |k, v| @word.send("#{k}=", v) }
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,42 @@
1
+ require 'ox'
2
+
3
+ module LLT
4
+ class Review::Treebank::Parser
5
+ class OxHandler < Ox::Sax
6
+
7
+ include Review::Helpers::Parsing::Helper
8
+ include Helper
9
+
10
+ def parse(data)
11
+ Ox.sax_parse(self, data)
12
+ end
13
+
14
+ def start_element(name)
15
+ case name
16
+ when :word then @in_word = true
17
+ when :sentence then @in_sentence = true
18
+ end
19
+ end
20
+
21
+ def end_element(name)
22
+ case name
23
+ when :word then @in_word = false
24
+ when :sentence then @in_sentence = false
25
+ end
26
+ end
27
+
28
+ def attr(name, value)
29
+ case
30
+ when @in_word
31
+ if name == :id
32
+ register_word(value)
33
+ else
34
+ @word.send("#{name}=", value)
35
+ end
36
+ when @in_sentence
37
+ register_sentence(value) if name == :id
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,13 @@
1
+ module LLT
2
+ class Review::Treebank
3
+ class Parser
4
+ require 'llt/review/treebank/parser/helper'
5
+ autoload :NokogiriHandler, 'llt/review/treebank/parser/nokogiri_handler'
6
+ autoload :OxHandler, 'llt/review/treebank/parser/ox_handler'
7
+
8
+ include Review::Helpers::Parsing
9
+ end
10
+ end
11
+ end
12
+
13
+
@@ -0,0 +1,65 @@
1
+ module LLT
2
+ class Review::Treebank
3
+ class Postag
4
+ attr_reader :id
5
+
6
+ def initialize(postag)
7
+ @id = :postag
8
+ @postag = postag
9
+ end
10
+
11
+ def to_s
12
+ @postag
13
+ end
14
+
15
+ # A little violating... move this to Datapoints
16
+ def report
17
+ @report ||= begin
18
+ # Questionable what the total numbers of datapoints should be.
19
+ # Count empty points as well?
20
+ data = Report::Datapoints.new(@postag.size)
21
+ add_datapoints_container(data)
22
+ data.each_with_index do |(_, container), i|
23
+ rtr = container.reports_to_request
24
+ val = @postag[i]
25
+ next unless val && val != '-'
26
+ container.add(Report::Postag::Datapoint.new(rtr, val))
27
+ container.increment
28
+ end
29
+ data
30
+ end
31
+ end
32
+
33
+
34
+ # All these constants cannot stay. Hardcoding the meaning of every postag
35
+ # datapoint is a no-go.
36
+
37
+ POSTAG_SCHEMA = %i{
38
+ part_of_speech person number tense
39
+ mood voice gender case degree
40
+ }
41
+
42
+ def analysis
43
+ @analysis ||= begin
44
+ Hash[POSTAG_SCHEMA.zip(@postag.each_char)]
45
+ end
46
+ end
47
+
48
+ def datapoints
49
+ POSTAG_SCHEMA.size
50
+ end
51
+
52
+ PLURALIZED_POSTAG_SCHEMA = %i{
53
+ parts_of_speech persons numbers tenses
54
+ moods voices genders cases degrees
55
+ }
56
+
57
+ CONTAINER_TABLE = PLURALIZED_POSTAG_SCHEMA.zip(POSTAG_SCHEMA)
58
+ def add_datapoints_container(data)
59
+ CONTAINER_TABLE.each do |pl, sg|
60
+ data.add(Report::Generic.new(pl, 0, sg))
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,12 @@
1
+ module LLT
2
+ class Review::Treebank::Report
3
+ class Datapoints < Generic
4
+ include Review::Helpers::Reportable
5
+
6
+ def initialize(total = 1)
7
+ super(:datapoints, total)
8
+ end
9
+ end
10
+ end
11
+ end
12
+
@@ -0,0 +1,10 @@
1
+ module LLT
2
+ class Review::Treebank::Report
3
+ class Generic < Review::Common::Report::Generic
4
+ def collect_reports(words)
5
+ return unless @reports_to_request
6
+ words.each { |_, word| add(word[@reports_to_request].report) }
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,8 @@
1
+ module LLT
2
+ class Review::Treebank::Report
3
+ class Lemma
4
+ include Review::Helpers::Reportable
5
+ end
6
+ end
7
+ end
8
+
@@ -0,0 +1,16 @@
1
+ module LLT
2
+ class Review::Treebank::Report::Postag
3
+ class Datapoint
4
+ include Review::Helpers::Reportable
5
+
6
+ def initialize(tag, id, total = 1)
7
+ super(id, total)
8
+ @tag = tag
9
+ end
10
+
11
+ def xml_tag
12
+ @tag
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,7 @@
1
+ module LLT
2
+ class Review::Treebank::Report
3
+ class Postag
4
+ include Review::Helpers::Reportable
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,27 @@
1
+ module LLT
2
+ class Review::Treebank::Report
3
+ class Postags < Generic
4
+ def initialize(total = 1)
5
+ super(:postags, total)
6
+ end
7
+
8
+ def collect_reports(words)
9
+ words.each do |_, word|
10
+ postag = word[:postag]
11
+ add(Postag.new(postag.to_s))
12
+ add(postag.report)
13
+ end
14
+ end
15
+
16
+ # Sorting is all good, but we want the postags to show up
17
+ # in front of the datapoints
18
+ def sort
19
+ shifter = :datapoints
20
+ sorted = super
21
+ sorted[shifter] = sorted.delete(shifter)
22
+ sorted
23
+ end
24
+ end
25
+ end
26
+ end
27
+
@@ -0,0 +1,7 @@
1
+ module LLT
2
+ class Review::Treebank::Report
3
+ class Relation
4
+ include Review::Helpers::Reportable
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,19 @@
1
+ module LLT
2
+ class Review::Treebank
3
+ class Report < Review::Common::Report
4
+ require 'llt/review/treebank/report/generic'
5
+ require 'llt/review/treebank/report/datapoints'
6
+ require 'llt/review/treebank/report/postags'
7
+ require 'llt/review/treebank/report/lemma'
8
+ require 'llt/review/treebank/report/postag'
9
+ require 'llt/review/treebank/report/postag/datapoint'
10
+ require 'llt/review/treebank/report/relation'
11
+
12
+ private
13
+
14
+ def namespace
15
+ Report
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,6 @@
1
+ module LLT
2
+ class Review::Treebank
3
+ class Reviewable < Review::Common::Reviewable
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,25 @@
1
+ module LLT
2
+ class Review::Treebank
3
+ class Sentence < Review::Common::Sentence
4
+ private
5
+
6
+ def report_container
7
+ reports = {
8
+ words: nil,
9
+ heads: nil,
10
+ relations: :relation,
11
+ lemmata: :lemma,
12
+ }
13
+
14
+ reports.each_with_object({}) do |(tag, requested), hsh|
15
+ hsh[tag] = Report::Generic.new(tag, size, requested)
16
+ end.merge(postags: Report::Postags.new(size))
17
+ end
18
+
19
+ def diff_namespace
20
+ Review::Treebank::Difference
21
+ end
22
+ end
23
+ end
24
+ end
25
+
@@ -0,0 +1,53 @@
1
+ module LLT
2
+ class Review::Treebank
3
+ class Word
4
+ include Core::Structures::HashContainable
5
+
6
+ attr_accessor :form, :lemma, :head, :relation
7
+ attr_reader :postag
8
+
9
+ Attr = Struct.new(:id, :attribute) do
10
+ def to_s
11
+ attribute
12
+ end
13
+
14
+ def report
15
+ @report ||= Report.const_get(id.capitalize).new(attribute)
16
+ end
17
+ end
18
+
19
+ %i{ lemma head relation }.each do |type|
20
+ define_method("#{type}=") { |val| add(Attr.new(type, val)) }
21
+ end
22
+
23
+ def postag=(tag)
24
+ add(Postag.new(tag))
25
+ end
26
+
27
+ COMPARABLE_ELEMENTS = %i{ lemma postag head relation }
28
+
29
+ def compare(other, diff_container, comparables)
30
+ comparables = COMPARABLE_ELEMENTS unless comparables # default value
31
+ comparables.each do |comparator|
32
+ a, b = [self, other].map { |w| w[comparator].to_s }
33
+ if a != b
34
+ d = diff_container[id] ||= Difference::Word.new(self)
35
+ d.add(new_difference(comparator, a, b))
36
+ end
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def new_difference(comparator, original, new)
43
+ klass = Difference.const_get(comparator.capitalize)
44
+ klass.new(self[comparator], original, new)
45
+ end
46
+
47
+ # used when parsers try to check in attributes we are not interested in
48
+ def method_missing(meth, *args, &blk)
49
+ super unless meth =~ /=$/
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,22 @@
1
+ module LLT
2
+ class Review::Treebank < Review
3
+ require 'llt/review/treebank/parser'
4
+
5
+ require 'llt/review/treebank/report'
6
+ require 'llt/review/treebank/gold'
7
+ require 'llt/review/treebank/reviewable'
8
+ require 'llt/review/treebank/comparison'
9
+
10
+ require 'llt/review/treebank/sentence'
11
+ require 'llt/review/treebank/word'
12
+ require 'llt/review/treebank/postag'
13
+
14
+ require 'llt/review/treebank/difference'
15
+
16
+ private
17
+
18
+ def root_identifier
19
+ 'treebank'
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,5 @@
1
+ module LLT
2
+ class Review
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
data/lib/llt/review.rb ADDED
@@ -0,0 +1,118 @@
1
+ require 'llt/core/api/helpers'
2
+ require 'llt/core/structures/hash_containable'
3
+ require 'llt/core/structures/hash_containable/generic'
4
+ require "llt/review/version"
5
+
6
+ module LLT
7
+ # This is pretty much the only messy class this whole gem contains.
8
+ # Do something about it!
9
+ class Review
10
+ require 'llt/review/helpers'
11
+
12
+ require 'llt/review/common'
13
+ require 'llt/review/treebank'
14
+ require 'llt/review/alignment'
15
+
16
+ include Core::Api::Helpers
17
+
18
+ def diff(gold, reviewables, comparables = nil)
19
+ parses = parse_files(Gold: gold, Reviewable: reviewables)
20
+
21
+ @gold, @reviewables = parses.partition do |parse_data|
22
+ parse_data.instance_of?(self.class.const_get(:Gold))
23
+ end
24
+
25
+ compare(comparables)
26
+ diff_report
27
+ all_diffs
28
+ end
29
+
30
+ def report(*uris)
31
+ @reports = parse_files(Report: uris)
32
+ @reports.each(&:report)
33
+ @reports
34
+ end
35
+
36
+ def to_xml(type = :diff)
37
+ root_name = "#{root_identifier}-#{type}"
38
+ XML_DECLARATION + wrap_with_tag(root_name, header + send("#{type}_to_xml"))
39
+ end
40
+
41
+ def all_diffs
42
+ @all_diffs ||= @reviewables.map do |reviewable|
43
+ reviewable.diff.values
44
+ end.flatten
45
+ end
46
+ alias_method :diffs, :all_diffs
47
+ alias_method :comparisons, :all_diffs
48
+
49
+ private
50
+
51
+ def diff_report
52
+ if @reviewables.one?
53
+ all_diffs.each(&:report)
54
+ else
55
+ diff_report_with_cloned_reports
56
+ end
57
+ end
58
+
59
+ # Check the comment at Comparison#report for more info
60
+ def diff_report_with_cloned_reports
61
+ used_golds = []
62
+ all_diffs.each do |d|
63
+ d.report(to_clone_or_not_to_clone?(used_golds, d.gold.id))
64
+ end
65
+ end
66
+
67
+ def to_clone_or_not_to_clone?(used, id)
68
+ used.include?(id) ? true : (used << id; false)
69
+ end
70
+
71
+ def compare(comparables = nil)
72
+ @gold.each do |gold|
73
+ @reviewables.each { |reviewable| reviewable.compare(gold, comparables) }
74
+ end
75
+ end
76
+
77
+ def parse_files(files)
78
+ to_parse = files.flat_map { |klass, uris| uris.map { |uri| [klass, uri] } }
79
+ parse_threaded(to_parse)
80
+ end
81
+
82
+ def parse_threaded(uris_with_classes)
83
+ threads = uris_with_classes.map do |klass, uri|
84
+ Thread.new do
85
+ data = get_from_uri(uri)
86
+ self.class.const_get(klass).new(uri, parse(data))
87
+ end
88
+ end
89
+ threads.map { |t| t.join; t.value }
90
+ end
91
+
92
+ def header
93
+ wrap_with_tag('files', header_files.map(&:xml_heading).join)
94
+ end
95
+
96
+ def header_files
97
+ [@gold, @reviewables, @reports].flatten.compact
98
+ end
99
+
100
+ def wrap_with_tag(tag, content)
101
+ "<#{tag}>" +
102
+ content +
103
+ "</#{tag}>"
104
+ end
105
+
106
+ def diff_to_xml
107
+ wrap_with_tag(:comparisons, @reviewables.map(&:to_xml).join)
108
+ end
109
+
110
+ def report_to_xml
111
+ wrap_with_tag(:reports, @reports.map(&:to_xml).join)
112
+ end
113
+
114
+ def parse(data)
115
+ self.class.const_get(:Parser).new.parse(data)
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'llt/review/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "llt-review"
8
+ spec.version = LLT::Review::VERSION
9
+ spec.authors = ["LFDM"]
10
+ spec.email = ["1986gh@gmail.com"]
11
+ spec.summary = %q{Reviews annotations}
12
+ spec.description = spec.summary
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.5"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ spec.add_development_dependency "simplecov", "~> 0.7"
25
+ end