opener-opinion-detector 1.0.0
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 +7 -0
- data/README.md +225 -0
- data/bin/opinion-detector +6 -0
- data/bin/opinion-detector-server +10 -0
- data/config.ru +4 -0
- data/lib/opener/opinion_detector.rb +90 -0
- data/lib/opener/opinion_detector/cli.rb +84 -0
- data/lib/opener/opinion_detector/public/markdown.css +283 -0
- data/lib/opener/opinion_detector/server.rb +29 -0
- data/lib/opener/opinion_detector/version.rb +5 -0
- data/lib/opener/opinion_detector/views/index.erb +281 -0
- data/lib/opener/opinion_detector/views/result.erb +15 -0
- data/opener-opinion-detector.gemspec +33 -0
- metadata +183 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 04c5af868b17a2e60d8a4ce8f5bfbd32842129fa
|
4
|
+
data.tar.gz: 0348514671da532342f41d71011b226705cadb14
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 633377edd6cf4606e8e24841a8de9ca654008b8c8e6eda5a97c0b564d08969e916e9370c73d25e045ac2baff415021a37534b1c7c81933d05bfa21599e18b49d
|
7
|
+
data.tar.gz: d58166aa6337bc845cb0d542cd7810829e26a2d874542978c39cb7efe8889bd41c6e31428bb7392dfd6ea3a8d603d128d7babe95c5440f38464a79329acf9c2a
|
data/README.md
ADDED
@@ -0,0 +1,225 @@
|
|
1
|
+
# OpinionDetector
|
2
|
+
|
3
|
+
Component that wraps the different existing Opinion Detectors.
|
4
|
+
|
5
|
+
## Requirements
|
6
|
+
|
7
|
+
* Perl 5
|
8
|
+
* Ruby 1.9.2 or newer
|
9
|
+
* Make
|
10
|
+
|
11
|
+
## Developers
|
12
|
+
|
13
|
+
See how to edit / change / compile this gem at the bottom of this file.
|
14
|
+
|
15
|
+
## Installation
|
16
|
+
|
17
|
+
### As part of a Gemfile in a Ruby application
|
18
|
+
|
19
|
+
Add this line to your application's Gemfile:
|
20
|
+
|
21
|
+
gem 'opener-opinion-detector',
|
22
|
+
:git=>"git@github.com:opener-project/opinion-detector.git"
|
23
|
+
|
24
|
+
And then execute:
|
25
|
+
|
26
|
+
$ bundle install
|
27
|
+
|
28
|
+
### As a standalone GEM:
|
29
|
+
|
30
|
+
Make sure you have the ```specific_install``` gem installed first by running
|
31
|
+
|
32
|
+
$ gem install specific_install
|
33
|
+
|
34
|
+
After that you can install the gem from the git repository like this:
|
35
|
+
|
36
|
+
$ gem specific_install opener-opinion-detector \
|
37
|
+
-l https://github.com/opener-project/opinion-detector.git
|
38
|
+
|
39
|
+
Once the gem is installed you have access to the following command from
|
40
|
+
anywhere on your computer:
|
41
|
+
|
42
|
+
$ cat englist.kaf | opinion-detector
|
43
|
+
|
44
|
+
or you can launch a webservice with
|
45
|
+
|
46
|
+
$ opinion-detector-server
|
47
|
+
|
48
|
+
KAF file text:
|
49
|
+
|
50
|
+
<?xml version='1.0' encoding='UTF-8'?>
|
51
|
+
<KAF xml:lang="en">
|
52
|
+
<kafHeader>
|
53
|
+
<linguisticProcessors layer="text">
|
54
|
+
<lp timestamp="2013-04-11T09:21:29CEST" version="1.0" name="Open-nlp sentence splitter"/>
|
55
|
+
<lp timestamp="2013-04-11T09:21:29CEST" version="1.0" name="Open-nlp tokenizer"/>
|
56
|
+
</linguisticProcessors>
|
57
|
+
<linguisticProcessor layer="terms">
|
58
|
+
<lp timestamp="2013-04-11T09:23:08CEST" version="1.0" name="Basic_polarity_tagger_with_pos"/>
|
59
|
+
</linguisticProcessor>
|
60
|
+
<linguisticProcessor layer="term">
|
61
|
+
<lp timestamp="2013-04-11T09:23:07CEST" version="1.0" name="TreeTagger_from_kaf"/>
|
62
|
+
</linguisticProcessor>
|
63
|
+
</kafHeader>
|
64
|
+
<text>
|
65
|
+
<wf wid="w_1" sent="s_1">This</wf>
|
66
|
+
<wf wid="w_2" sent="s_1">is</wf>
|
67
|
+
<wf wid="w_3" sent="s_1">a</wf>
|
68
|
+
<wf wid="w_4" sent="s_1">very</wf>
|
69
|
+
<wf wid="w_5" sent="s_1">nice</wf>
|
70
|
+
<wf wid="w_6" sent="s_1">hotel</wf>
|
71
|
+
<wf wid="w_7" sent="s_1">in</wf>
|
72
|
+
<wf wid="w_8" sent="s_1">Amsterdam</wf>
|
73
|
+
</text>
|
74
|
+
<terms>
|
75
|
+
<term tid="t_1" lemma="this" morphofeat="DT" type="close" pos="D">
|
76
|
+
<span>
|
77
|
+
<target id="w_1"/>
|
78
|
+
</span>
|
79
|
+
</term>
|
80
|
+
<term tid="t_2" lemma="be" morphofeat="VBZ" type="open" pos="V">
|
81
|
+
<span>
|
82
|
+
<target id="w_2"/>
|
83
|
+
</span>
|
84
|
+
</term>
|
85
|
+
<term tid="t_3" lemma="a" morphofeat="DT" type="close" pos="D">
|
86
|
+
<span>
|
87
|
+
<target id="w_3"/>
|
88
|
+
</span>
|
89
|
+
</term>
|
90
|
+
<term tid="t_4" lemma="very" morphofeat="RB" type="open" pos="A">
|
91
|
+
<span>
|
92
|
+
<target id="w_4"/>
|
93
|
+
</span>
|
94
|
+
<sentiment sentiment_modifier="intensifier" resource="VUA_olery_lexicon_en_lmf"/>
|
95
|
+
</term>
|
96
|
+
<term tid="t_5" lemma="nice" morphofeat="JJ" type="open" pos="G">
|
97
|
+
<span>
|
98
|
+
<target id="w_5"/>
|
99
|
+
</span>
|
100
|
+
<sentiment polarity="positive" resource="VUA_olery_lexicon_en_lmf"/>
|
101
|
+
</term>
|
102
|
+
<term tid="t_6" lemma="hotel" morphofeat="NN" type="open" pos="N">
|
103
|
+
<span>
|
104
|
+
<target id="w_6"/>
|
105
|
+
</span>
|
106
|
+
</term>
|
107
|
+
<term tid="t_7" lemma="in" morphofeat="IN" type="close" pos="P">
|
108
|
+
<span>
|
109
|
+
<target id="w_7"/>
|
110
|
+
</span>
|
111
|
+
</term>
|
112
|
+
<term tid="t_8" lemma="Amsterdam" morphofeat="NP" type="open" pos="R">
|
113
|
+
<span>
|
114
|
+
<target id="w_8"/>
|
115
|
+
</span>
|
116
|
+
</term>
|
117
|
+
</terms>
|
118
|
+
<entities>
|
119
|
+
<entity eid="e15" type="location">
|
120
|
+
<references>
|
121
|
+
<span>
|
122
|
+
<!--Amsterdam -->
|
123
|
+
<target id="t_8" />
|
124
|
+
</span>
|
125
|
+
</references>
|
126
|
+
</entity>
|
127
|
+
</entities>
|
128
|
+
</KAF>
|
129
|
+
|
130
|
+
|
131
|
+
Enjoy!
|
132
|
+
|
133
|
+
## Usage
|
134
|
+
|
135
|
+
Detecting opinion for some text (assuming that the above text is in a file called *english.kaf*):
|
136
|
+
|
137
|
+
cat english.kaf | opinion-detector
|
138
|
+
|
139
|
+
|
140
|
+
Will result in
|
141
|
+
|
142
|
+
<?xml version='1.0' encoding='UTF-8'?>
|
143
|
+
<KAF version="v1.opener" xml:lang="en">
|
144
|
+
<kafHeader>
|
145
|
+
<linguisticProcessors layer="text">
|
146
|
+
<lp name="opennlp-en-tok" timestamp="2013-06-11T13:41:37Z" version="1.0"/>
|
147
|
+
<lp name="opennlp-en-sent" timestamp="2013-06-11T13:41:37Z" version="1.0"/>
|
148
|
+
</linguisticProcessors>
|
149
|
+
<linguisticProcessor layer="term">
|
150
|
+
<lp timestamp="2013-06-12T15:18:03CEST" version="1.0" name="Open nlp pos tagger"/>
|
151
|
+
</linguisticProcessor>
|
152
|
+
</kafHeader>
|
153
|
+
<text>
|
154
|
+
<wf length="4" offset="0" para="1" sent="1" wid="w1">this</wf>
|
155
|
+
<wf length="2" offset="5" para="1" sent="1" wid="w2">is</wf>
|
156
|
+
<wf length="2" offset="8" para="1" sent="1" wid="w3">an</wf>
|
157
|
+
<wf length="7" offset="11" para="1" sent="1" wid="w4">english</wf>
|
158
|
+
<wf length="4" offset="19" para="1" sent="1" wid="w5">text</wf>
|
159
|
+
</text>
|
160
|
+
<terms>
|
161
|
+
<term lemma="this" morphofeat="FM" pos="O" tid="t_1" type="open">
|
162
|
+
<span>
|
163
|
+
<target id="w1"/>
|
164
|
+
</span>
|
165
|
+
</term>
|
166
|
+
<term lemma="is" morphofeat="FM" pos="O" tid="t_2" type="open">
|
167
|
+
<span>
|
168
|
+
<target id="w2"/>
|
169
|
+
</span>
|
170
|
+
</term>
|
171
|
+
<term lemma="an" morphofeat="APPR" pos="P" tid="t_3" type="close">
|
172
|
+
<span>
|
173
|
+
<target id="w3"/>
|
174
|
+
</span>
|
175
|
+
</term>
|
176
|
+
<term lemma="english" morphofeat="FM" pos="O" tid="t_4" type="open">
|
177
|
+
<span>
|
178
|
+
<target id="w4"/>
|
179
|
+
</span>
|
180
|
+
</term>
|
181
|
+
<term lemma="text" morphofeat="FM" pos="O" tid="t_5" type="open">
|
182
|
+
<span>
|
183
|
+
<target id="w5"/>
|
184
|
+
</span>
|
185
|
+
</term>
|
186
|
+
</terms>
|
187
|
+
</KAF>
|
188
|
+
|
189
|
+
## Server
|
190
|
+
|
191
|
+
The Opinion Detector comes equipped with a simple webservice. To start the
|
192
|
+
webservice type:
|
193
|
+
|
194
|
+
opinion-detector-server
|
195
|
+
|
196
|
+
This will launch a mini webserver with the webservice. It defaults to port 9292,
|
197
|
+
so you can access it at:
|
198
|
+
|
199
|
+
http://localhost:9292
|
200
|
+
|
201
|
+
To launch it on a different port provide the ```-p [port-number]``` option like
|
202
|
+
this:
|
203
|
+
|
204
|
+
opinion-detector-server -p 1234
|
205
|
+
|
206
|
+
It then launches at ```http://localhost:1234```
|
207
|
+
|
208
|
+
Documentation on the Webservice is provided by surfing to the urls provided
|
209
|
+
above.
|
210
|
+
|
211
|
+
|
212
|
+
## Contributing
|
213
|
+
|
214
|
+
### Procedure
|
215
|
+
|
216
|
+
1. Pull it
|
217
|
+
2. Create your feature branch (`git checkout -b features/my-new-feature`)
|
218
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
219
|
+
4. Push to the branch (`git push origin features/my-new-feature`)
|
220
|
+
5. If you're confident, merge your changes into master.
|
221
|
+
|
222
|
+
# What's next?
|
223
|
+
|
224
|
+
If you're interested in the pos_tagger, you also might want to check
|
225
|
+
out opener-project/opinion-detector.
|
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rack'
|
4
|
+
|
5
|
+
# Without calling `Rack::Server#options` manually the CLI arguments will never
|
6
|
+
# be passed, thus the application can't be specified as a constructor argument.
|
7
|
+
server = Rack::Server.new
|
8
|
+
server.options[:config] = File.expand_path('../../config.ru', __FILE__)
|
9
|
+
|
10
|
+
server.start
|
data/config.ru
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'opener/opinion_detectors/base'
|
2
|
+
require 'open3'
|
3
|
+
require 'nokogiri'
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
require_relative 'opinion_detector/version'
|
7
|
+
require_relative 'opinion_detector/cli'
|
8
|
+
|
9
|
+
module Opener
|
10
|
+
##
|
11
|
+
# Primary opinion detector class that delegates work to the various opinion
|
12
|
+
# detector kernels.
|
13
|
+
#
|
14
|
+
# @!attribute [r] options
|
15
|
+
# @return [Hash]
|
16
|
+
#
|
17
|
+
class OpinionDetector
|
18
|
+
attr_reader :options
|
19
|
+
|
20
|
+
##
|
21
|
+
# Hash containing the default options to use.
|
22
|
+
#
|
23
|
+
# @return [Hash]
|
24
|
+
#
|
25
|
+
DEFAULT_OPTIONS = {
|
26
|
+
:args => []
|
27
|
+
}.freeze
|
28
|
+
|
29
|
+
##
|
30
|
+
# @param [Hash] options
|
31
|
+
#
|
32
|
+
# @option options [Array] :args Collection of arbitrary arguments to pass
|
33
|
+
# to the individual tokenizer commands.
|
34
|
+
#
|
35
|
+
def initialize(options = {})
|
36
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# Processes the input and returns an array containing the output of STDOUT,
|
41
|
+
# STDERR and an object containing process information.
|
42
|
+
#
|
43
|
+
# @param [String] input
|
44
|
+
# @return [Array]
|
45
|
+
#
|
46
|
+
def run(input)
|
47
|
+
language = language_from_kaf(input)
|
48
|
+
|
49
|
+
unless valid_language?(language)
|
50
|
+
raise ArgumentError, "The specified language (#{language}) is invalid"
|
51
|
+
end
|
52
|
+
|
53
|
+
kernel = language_constant(language).new(:args => options[:args])
|
54
|
+
return kernel.run(input)
|
55
|
+
end
|
56
|
+
|
57
|
+
protected
|
58
|
+
|
59
|
+
##
|
60
|
+
# Extracts the language from a KAF document.
|
61
|
+
#
|
62
|
+
# @param [String] input
|
63
|
+
# @return [String]
|
64
|
+
#
|
65
|
+
def language_from_kaf(input)
|
66
|
+
reader = Nokogiri::XML::Reader(input)
|
67
|
+
|
68
|
+
return reader.read.lang
|
69
|
+
end
|
70
|
+
|
71
|
+
##
|
72
|
+
# @param [String] language
|
73
|
+
# @return [Class]
|
74
|
+
#
|
75
|
+
def language_constant(language)
|
76
|
+
Opener::OpinionDetectors.const_get(language.upcase)
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# @return [TrueClass|FalseClass]
|
81
|
+
#
|
82
|
+
def valid_language?(language)
|
83
|
+
if language
|
84
|
+
return Opener::OpinionDetectors.const_defined?(language.upcase)
|
85
|
+
else
|
86
|
+
return false
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end # OpinionDetector
|
90
|
+
end # Opener
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Opener
|
2
|
+
class OpinionDetector
|
3
|
+
##
|
4
|
+
# CLI wrapper around {Opener::OpinionDetector} using OptionParser.
|
5
|
+
#
|
6
|
+
# @!attribute [r] options
|
7
|
+
# @return [Hash]
|
8
|
+
# @!attribute [r] option_parser
|
9
|
+
# @return [OptionParser]
|
10
|
+
#
|
11
|
+
class CLI
|
12
|
+
attr_reader :options, :option_parser
|
13
|
+
|
14
|
+
##
|
15
|
+
# @param [Hash] options
|
16
|
+
#
|
17
|
+
def initialize(options = {})
|
18
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
19
|
+
|
20
|
+
@option_parser = OptionParser.new do |opts|
|
21
|
+
opts.program_name = 'opinion-detector'
|
22
|
+
opts.summary_indent = ' '
|
23
|
+
|
24
|
+
opts.on('-h', '--help', 'Shows this help message') do
|
25
|
+
show_help
|
26
|
+
end
|
27
|
+
|
28
|
+
opts.on('-v', '--version', 'Shows the current version') do
|
29
|
+
show_version
|
30
|
+
end
|
31
|
+
|
32
|
+
opts.on('-l', '--log', 'Enables logging to STDERR') do
|
33
|
+
@options[:logging] = true
|
34
|
+
end
|
35
|
+
|
36
|
+
opts.separator <<-EOF
|
37
|
+
|
38
|
+
Examples:
|
39
|
+
|
40
|
+
cat example.kaf | #{opts.program_name}
|
41
|
+
cat example.kaf | #{opts.program_name} -l # Enables logging to STDERR
|
42
|
+
EOF
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
##
|
47
|
+
# @param [String] input
|
48
|
+
#
|
49
|
+
def run(input)
|
50
|
+
option_parser.parse!(options[:args])
|
51
|
+
|
52
|
+
tagger = OpinionDetector.new(options)
|
53
|
+
|
54
|
+
stdout, stderr, process = tagger.run(input)
|
55
|
+
|
56
|
+
if process.success?
|
57
|
+
puts stdout
|
58
|
+
|
59
|
+
if options[:logging] and !stderr.empty?
|
60
|
+
STDERR.puts(stderr)
|
61
|
+
end
|
62
|
+
else
|
63
|
+
abort stderr
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
##
|
70
|
+
# Shows the help message and exits the program.
|
71
|
+
#
|
72
|
+
def show_help
|
73
|
+
abort option_parser.to_s
|
74
|
+
end
|
75
|
+
|
76
|
+
##
|
77
|
+
# Shows the version and exits the program.
|
78
|
+
#
|
79
|
+
def show_version
|
80
|
+
abort "#{option_parser.program_name} v#{VERSION} on #{RUBY_DESCRIPTION}"
|
81
|
+
end
|
82
|
+
end # CLI
|
83
|
+
end # OpinionDetector
|
84
|
+
end # Opener
|
@@ -0,0 +1,283 @@
|
|
1
|
+
input[type="text"], textarea
|
2
|
+
{
|
3
|
+
width: 500px;
|
4
|
+
}
|
5
|
+
|
6
|
+
body {
|
7
|
+
font-family: Helvetica, arial, sans-serif;
|
8
|
+
font-size: 14px;
|
9
|
+
line-height: 1.6;
|
10
|
+
padding-top: 10px;
|
11
|
+
padding-bottom: 10px;
|
12
|
+
background-color: white;
|
13
|
+
padding: 30px; }
|
14
|
+
|
15
|
+
body > *:first-child {
|
16
|
+
margin-top: 0 !important; }
|
17
|
+
body > *:last-child {
|
18
|
+
margin-bottom: 0 !important; }
|
19
|
+
|
20
|
+
a {
|
21
|
+
color: #4183C4; }
|
22
|
+
a.absent {
|
23
|
+
color: #cc0000; }
|
24
|
+
a.anchor {
|
25
|
+
display: block;
|
26
|
+
padding-left: 30px;
|
27
|
+
margin-left: -30px;
|
28
|
+
cursor: pointer;
|
29
|
+
position: absolute;
|
30
|
+
top: 0;
|
31
|
+
left: 0;
|
32
|
+
bottom: 0; }
|
33
|
+
|
34
|
+
h1, h2, h3, h4, h5, h6 {
|
35
|
+
margin: 20px 0 10px;
|
36
|
+
padding: 0;
|
37
|
+
font-weight: bold;
|
38
|
+
-webkit-font-smoothing: antialiased;
|
39
|
+
cursor: text;
|
40
|
+
position: relative; }
|
41
|
+
|
42
|
+
h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor {
|
43
|
+
background: url("../../images/modules/styleguide/para.png") no-repeat 10px center;
|
44
|
+
text-decoration: none; }
|
45
|
+
|
46
|
+
h1 tt, h1 code {
|
47
|
+
font-size: inherit; }
|
48
|
+
|
49
|
+
h2 tt, h2 code {
|
50
|
+
font-size: inherit; }
|
51
|
+
|
52
|
+
h3 tt, h3 code {
|
53
|
+
font-size: inherit; }
|
54
|
+
|
55
|
+
h4 tt, h4 code {
|
56
|
+
font-size: inherit; }
|
57
|
+
|
58
|
+
h5 tt, h5 code {
|
59
|
+
font-size: inherit; }
|
60
|
+
|
61
|
+
h6 tt, h6 code {
|
62
|
+
font-size: inherit; }
|
63
|
+
|
64
|
+
h1 {
|
65
|
+
font-size: 28px;
|
66
|
+
color: black; }
|
67
|
+
|
68
|
+
h2 {
|
69
|
+
font-size: 24px;
|
70
|
+
border-bottom: 1px solid #cccccc;
|
71
|
+
color: black; }
|
72
|
+
|
73
|
+
h3 {
|
74
|
+
font-size: 18px; }
|
75
|
+
|
76
|
+
h4 {
|
77
|
+
font-size: 16px; }
|
78
|
+
|
79
|
+
h5 {
|
80
|
+
font-size: 14px; }
|
81
|
+
|
82
|
+
h6 {
|
83
|
+
color: #777777;
|
84
|
+
font-size: 14px; }
|
85
|
+
|
86
|
+
p, blockquote, ul, ol, dl, li, table, pre {
|
87
|
+
margin: 15px 0; }
|
88
|
+
|
89
|
+
hr {
|
90
|
+
background: transparent url("../../images/modules/pulls/dirty-shade.png") repeat-x 0 0;
|
91
|
+
border: 0 none;
|
92
|
+
color: #cccccc;
|
93
|
+
height: 4px;
|
94
|
+
padding: 0; }
|
95
|
+
|
96
|
+
body > h2:first-child {
|
97
|
+
margin-top: 0;
|
98
|
+
padding-top: 0; }
|
99
|
+
body > h1:first-child {
|
100
|
+
margin-top: 0;
|
101
|
+
padding-top: 0; }
|
102
|
+
body > h1:first-child + h2 {
|
103
|
+
margin-top: 0;
|
104
|
+
padding-top: 0; }
|
105
|
+
body > h3:first-child, body > h4:first-child, body > h5:first-child, body > h6:first-child {
|
106
|
+
margin-top: 0;
|
107
|
+
padding-top: 0; }
|
108
|
+
|
109
|
+
a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
|
110
|
+
margin-top: 0;
|
111
|
+
padding-top: 0; }
|
112
|
+
|
113
|
+
h1 p, h2 p, h3 p, h4 p, h5 p, h6 p {
|
114
|
+
margin-top: 0; }
|
115
|
+
|
116
|
+
li p.first {
|
117
|
+
display: inline-block; }
|
118
|
+
|
119
|
+
ul, ol {
|
120
|
+
padding-left: 30px; }
|
121
|
+
|
122
|
+
ul :first-child, ol :first-child {
|
123
|
+
margin-top: 0; }
|
124
|
+
|
125
|
+
ul :last-child, ol :last-child {
|
126
|
+
margin-bottom: 0; }
|
127
|
+
|
128
|
+
dl {
|
129
|
+
padding: 0; }
|
130
|
+
dl dt {
|
131
|
+
font-size: 14px;
|
132
|
+
font-weight: bold;
|
133
|
+
font-style: italic;
|
134
|
+
padding: 0;
|
135
|
+
margin: 15px 0 5px; }
|
136
|
+
dl dt:first-child {
|
137
|
+
padding: 0; }
|
138
|
+
dl dt > :first-child {
|
139
|
+
margin-top: 0; }
|
140
|
+
dl dt > :last-child {
|
141
|
+
margin-bottom: 0; }
|
142
|
+
dl dd {
|
143
|
+
margin: 0 0 15px;
|
144
|
+
padding: 0 15px; }
|
145
|
+
dl dd > :first-child {
|
146
|
+
margin-top: 0; }
|
147
|
+
dl dd > :last-child {
|
148
|
+
margin-bottom: 0; }
|
149
|
+
|
150
|
+
blockquote {
|
151
|
+
border-left: 4px solid #dddddd;
|
152
|
+
padding: 0 15px;
|
153
|
+
color: #777777; }
|
154
|
+
blockquote > :first-child {
|
155
|
+
margin-top: 0; }
|
156
|
+
blockquote > :last-child {
|
157
|
+
margin-bottom: 0; }
|
158
|
+
|
159
|
+
table {
|
160
|
+
padding: 0; }
|
161
|
+
table tr {
|
162
|
+
border-top: 1px solid #cccccc;
|
163
|
+
background-color: white;
|
164
|
+
margin: 0;
|
165
|
+
padding: 0; }
|
166
|
+
table tr:nth-child(2n) {
|
167
|
+
background-color: #f8f8f8; }
|
168
|
+
table tr th {
|
169
|
+
font-weight: bold;
|
170
|
+
border: 1px solid #cccccc;
|
171
|
+
text-align: left;
|
172
|
+
margin: 0;
|
173
|
+
padding: 6px 13px; }
|
174
|
+
table tr td {
|
175
|
+
border: 1px solid #cccccc;
|
176
|
+
text-align: left;
|
177
|
+
margin: 0;
|
178
|
+
padding: 6px 13px; }
|
179
|
+
table tr th :first-child, table tr td :first-child {
|
180
|
+
margin-top: 0; }
|
181
|
+
table tr th :last-child, table tr td :last-child {
|
182
|
+
margin-bottom: 0; }
|
183
|
+
|
184
|
+
img {
|
185
|
+
max-width: 100%; }
|
186
|
+
|
187
|
+
span.frame {
|
188
|
+
display: block;
|
189
|
+
overflow: hidden; }
|
190
|
+
span.frame > span {
|
191
|
+
border: 1px solid #dddddd;
|
192
|
+
display: block;
|
193
|
+
float: left;
|
194
|
+
overflow: hidden;
|
195
|
+
margin: 13px 0 0;
|
196
|
+
padding: 7px;
|
197
|
+
width: auto; }
|
198
|
+
span.frame span img {
|
199
|
+
display: block;
|
200
|
+
float: left; }
|
201
|
+
span.frame span span {
|
202
|
+
clear: both;
|
203
|
+
color: #333333;
|
204
|
+
display: block;
|
205
|
+
padding: 5px 0 0; }
|
206
|
+
span.align-center {
|
207
|
+
display: block;
|
208
|
+
overflow: hidden;
|
209
|
+
clear: both; }
|
210
|
+
span.align-center > span {
|
211
|
+
display: block;
|
212
|
+
overflow: hidden;
|
213
|
+
margin: 13px auto 0;
|
214
|
+
text-align: center; }
|
215
|
+
span.align-center span img {
|
216
|
+
margin: 0 auto;
|
217
|
+
text-align: center; }
|
218
|
+
span.align-right {
|
219
|
+
display: block;
|
220
|
+
overflow: hidden;
|
221
|
+
clear: both; }
|
222
|
+
span.align-right > span {
|
223
|
+
display: block;
|
224
|
+
overflow: hidden;
|
225
|
+
margin: 13px 0 0;
|
226
|
+
text-align: right; }
|
227
|
+
span.align-right span img {
|
228
|
+
margin: 0;
|
229
|
+
text-align: right; }
|
230
|
+
span.float-left {
|
231
|
+
display: block;
|
232
|
+
margin-right: 13px;
|
233
|
+
overflow: hidden;
|
234
|
+
float: left; }
|
235
|
+
span.float-left span {
|
236
|
+
margin: 13px 0 0; }
|
237
|
+
span.float-right {
|
238
|
+
display: block;
|
239
|
+
margin-left: 13px;
|
240
|
+
overflow: hidden;
|
241
|
+
float: right; }
|
242
|
+
span.float-right > span {
|
243
|
+
display: block;
|
244
|
+
overflow: hidden;
|
245
|
+
margin: 13px auto 0;
|
246
|
+
text-align: right; }
|
247
|
+
|
248
|
+
code, tt {
|
249
|
+
margin: 0 2px;
|
250
|
+
padding: 0 5px;
|
251
|
+
white-space: nowrap;
|
252
|
+
border: 1px solid #eaeaea;
|
253
|
+
background-color: #f8f8f8;
|
254
|
+
border-radius: 3px; }
|
255
|
+
|
256
|
+
pre code {
|
257
|
+
margin: 0;
|
258
|
+
padding: 0;
|
259
|
+
white-space: pre;
|
260
|
+
border: none;
|
261
|
+
background: transparent; }
|
262
|
+
|
263
|
+
.highlight pre {
|
264
|
+
background-color: #f8f8f8;
|
265
|
+
border: 1px solid #cccccc;
|
266
|
+
font-size: 13px;
|
267
|
+
line-height: 19px;
|
268
|
+
overflow: auto;
|
269
|
+
padding: 6px 10px;
|
270
|
+
border-radius: 3px; }
|
271
|
+
|
272
|
+
pre {
|
273
|
+
background-color: #f8f8f8;
|
274
|
+
border: 1px solid #cccccc;
|
275
|
+
font-size: 13px;
|
276
|
+
line-height: 19px;
|
277
|
+
overflow: auto;
|
278
|
+
padding: 6px 10px;
|
279
|
+
border-radius: 3px; }
|
280
|
+
pre code, pre tt {
|
281
|
+
background-color: transparent;
|
282
|
+
border: none; }
|
283
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'httpclient'
|
3
|
+
require 'opener/webservice'
|
4
|
+
|
5
|
+
module Opener
|
6
|
+
class OpinionDetector
|
7
|
+
##
|
8
|
+
# Opinion Detector server powered by Sinatra.
|
9
|
+
#
|
10
|
+
class Server < Webservice
|
11
|
+
set :views, File.expand_path('../views', __FILE__)
|
12
|
+
text_processor OpinionDetector
|
13
|
+
accepted_params :input
|
14
|
+
|
15
|
+
##
|
16
|
+
# @see Opener::Webservice#analyze
|
17
|
+
#
|
18
|
+
def analyze(*args)
|
19
|
+
begin
|
20
|
+
super
|
21
|
+
# ArgumentErrors are used for invalid languages. These happen too often
|
22
|
+
# so we'll supress them for now.
|
23
|
+
rescue ArgumentError => error
|
24
|
+
halt(400, error.message.strip)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end # Server
|
28
|
+
end # OpinionDetector
|
29
|
+
end # Opener
|
@@ -0,0 +1,281 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<link type="text/css" rel="stylesheet" charset="UTF-8" href="markdown.css"/>
|
5
|
+
<title>Opinion Detector Webservice</title>
|
6
|
+
</head>
|
7
|
+
<body>
|
8
|
+
<h1>Opinion Detector Web Service</h1>
|
9
|
+
|
10
|
+
<h2>Example Usage</h2>
|
11
|
+
|
12
|
+
<p>
|
13
|
+
<pre>opinion-detector-server start</pre>
|
14
|
+
<pre>curl -d 'input=<?xml version="1.0" encoding="UTF-8" standalone="no"?><KAF version="v1.opener" xml:lang="en"><kafHeader><linguisticProcessors layer="text"><lp name="opennlp-en-tok" timestamp="2013-06-11T13:41:37Z" version="1.0"/><lp name="opennlp-en-sent" timestamp="2013-06-11T13:41:37Z" version="1.0"/></linguisticProcessors></kafHeader><text><wf length="4" offset="0" para="1" sent="1" wid="w1">this</wf><wf length="2" offset="5" para="1" sent="1" wid="w2">is</wf><wf length="2" offset="8" para="1" sent="1" wid="w3">an</wf><wf length="7" offset="11" para="1" sent="1" wid="w4">english</wf><wf length="4" offset="19" para="1" sent="1" wid="w5">text</wf></text></KAF>' http://localhost:9292 -XPOST</pre>
|
15
|
+
|
16
|
+
outputs:
|
17
|
+
|
18
|
+
<pre>
|
19
|
+
<?xml version='1.0' encoding='UTF-8'?>
|
20
|
+
<KAF xml:lang="en">
|
21
|
+
<kafHeader>
|
22
|
+
<linguisticProcessors layer="text">
|
23
|
+
<lp timestamp="2013-04-11T09:21:29CEST" version="1.0" name="Open-nlp sentence splitter"/>
|
24
|
+
<lp timestamp="2013-04-11T09:21:29CEST" version="1.0" name="Open-nlp tokenizer"/>
|
25
|
+
</linguisticProcessors>
|
26
|
+
<linguisticProcessor layer="opinions">
|
27
|
+
<lp timestamp="2013-06-27T17:56:32EEST" version="1.0" name="Crfsuite machine learning opinion miner"/>
|
28
|
+
</linguisticProcessor>
|
29
|
+
<linguisticProcessor layer="terms">
|
30
|
+
<lp timestamp="2013-04-11T09:23:08CEST" version="1.0" name="Basic_polarity_tagger_with_pos"/>
|
31
|
+
</linguisticProcessor>
|
32
|
+
<linguisticProcessor layer="term">
|
33
|
+
<lp timestamp="2013-04-11T09:23:07CEST" version="1.0" name="TreeTagger_from_kaf"/>
|
34
|
+
</linguisticProcessor>
|
35
|
+
</kafHeader>
|
36
|
+
<text>
|
37
|
+
<wf wid="w_1" sent="s_1">This</wf>
|
38
|
+
<wf wid="w_2" sent="s_1">is</wf>
|
39
|
+
<wf wid="w_3" sent="s_1">a</wf>
|
40
|
+
<wf wid="w_4" sent="s_1">very</wf>
|
41
|
+
<wf wid="w_5" sent="s_1">nice</wf>
|
42
|
+
<wf wid="w_6" sent="s_1">hotel</wf>
|
43
|
+
<wf wid="w_7" sent="s_1">in</wf>
|
44
|
+
<wf wid="w_8" sent="s_1">Amsterdam</wf>
|
45
|
+
</text>
|
46
|
+
<terms>
|
47
|
+
<term tid="t_1" lemma="this" morphofeat="DT" type="close" pos="D">
|
48
|
+
<span>
|
49
|
+
<target id="w_1"/>
|
50
|
+
</span>
|
51
|
+
</term>
|
52
|
+
<term tid="t_2" lemma="be" morphofeat="VBZ" type="open" pos="V">
|
53
|
+
<span>
|
54
|
+
<target id="w_2"/>
|
55
|
+
</span>
|
56
|
+
</term>
|
57
|
+
<term tid="t_3" lemma="a" morphofeat="DT" type="close" pos="D">
|
58
|
+
<span>
|
59
|
+
<target id="w_3"/>
|
60
|
+
</span>
|
61
|
+
</term>
|
62
|
+
<term tid="t_4" lemma="very" morphofeat="RB" type="open" pos="A">
|
63
|
+
<span>
|
64
|
+
<target id="w_4"/>
|
65
|
+
</span>
|
66
|
+
<sentiment sentiment_modifier="intensifier" resource="VUA_olery_lexicon_en_lmf"/>
|
67
|
+
</term>
|
68
|
+
<term tid="t_5" lemma="nice" morphofeat="JJ" type="open" pos="G">
|
69
|
+
<span>
|
70
|
+
<target id="w_5"/>
|
71
|
+
</span>
|
72
|
+
<sentiment polarity="positive" resource="VUA_olery_lexicon_en_lmf"/>
|
73
|
+
</term>
|
74
|
+
<term tid="t_6" lemma="hotel" morphofeat="NN" type="open" pos="N">
|
75
|
+
<span>
|
76
|
+
<target id="w_6"/>
|
77
|
+
</span>
|
78
|
+
</term>
|
79
|
+
<term tid="t_7" lemma="in" morphofeat="IN" type="close" pos="P">
|
80
|
+
<span>
|
81
|
+
<target id="w_7"/>
|
82
|
+
</span>
|
83
|
+
</term>
|
84
|
+
<term tid="t_8" lemma="Amsterdam" morphofeat="NP" type="open" pos="R">
|
85
|
+
<span>
|
86
|
+
<target id="w_8"/>
|
87
|
+
</span>
|
88
|
+
</term>
|
89
|
+
</terms>
|
90
|
+
<entities>
|
91
|
+
<entity eid="e15" type="location">
|
92
|
+
<references>
|
93
|
+
<span>
|
94
|
+
<!--Amsterdam -->
|
95
|
+
<target id="t_8"/>
|
96
|
+
</span>
|
97
|
+
</references>
|
98
|
+
</entity>
|
99
|
+
</entities>
|
100
|
+
<opinions>
|
101
|
+
<opinion oid="o_1">
|
102
|
+
<opinion_holder>
|
103
|
+
<span/>
|
104
|
+
</opinion_holder>
|
105
|
+
<opinion_target>
|
106
|
+
<span>
|
107
|
+
<target id="t_1"/>
|
108
|
+
</span>
|
109
|
+
</opinion_target>
|
110
|
+
<opinion_expression polarity="positive" strength="1">
|
111
|
+
<span>
|
112
|
+
<target id="t_4"/>
|
113
|
+
<target id="t_5"/>
|
114
|
+
<target id="t_6"/>
|
115
|
+
<target id="t_7"/>
|
116
|
+
<target id="t_8"/>
|
117
|
+
</span>
|
118
|
+
</opinion_expression>
|
119
|
+
</opinion>
|
120
|
+
</opinions>
|
121
|
+
</KAF></pre>
|
122
|
+
</p>
|
123
|
+
|
124
|
+
<h2>Try the webservice</h2>
|
125
|
+
|
126
|
+
<p>* required</p>
|
127
|
+
<p>** When entering a value no response will be displayed in the browser.</p>
|
128
|
+
|
129
|
+
<form action="<%=url("/")%>" method="POST">
|
130
|
+
<div>
|
131
|
+
<label for="input"/>Type your text here*</label>
|
132
|
+
<br/>
|
133
|
+
|
134
|
+
<textarea name="input" id="text" rows="10" cols="50"/></textarea>
|
135
|
+
</div>
|
136
|
+
<% 10.times do |t| %>
|
137
|
+
<div>
|
138
|
+
<label for="callbacks">Callback URL <%=t+1%>(**)</label>
|
139
|
+
<br />
|
140
|
+
|
141
|
+
<input id="callbacks" type="text" name="callbacks[]" />
|
142
|
+
</div>
|
143
|
+
<% end %>
|
144
|
+
|
145
|
+
<div>
|
146
|
+
<label for="error_callback">Error Callback</label>
|
147
|
+
<br />
|
148
|
+
|
149
|
+
<input id="error_callback" type="text" name="error_callback" />
|
150
|
+
</div>
|
151
|
+
<input type="submit" value="Submit" />
|
152
|
+
</form>
|
153
|
+
|
154
|
+
<h2>Actions</h2>
|
155
|
+
|
156
|
+
<p>
|
157
|
+
<dl>
|
158
|
+
<dt>POST /</dt>
|
159
|
+
<dd>Detect opinion for input text. See arguments listing for more options.</dd>
|
160
|
+
<dt>GET /</dt>
|
161
|
+
<dd>Show this page</dd>
|
162
|
+
</dl>
|
163
|
+
</p>
|
164
|
+
|
165
|
+
<h2>Arguments</h2>
|
166
|
+
|
167
|
+
<p> The webservice takes the following arguments: </p>
|
168
|
+
<p>* required</p>
|
169
|
+
|
170
|
+
<dl>
|
171
|
+
<dt>text*</dt>
|
172
|
+
<dd>The input text in KAF format. Sample KAF input:</dd>
|
173
|
+
<pre>
|
174
|
+
<?xml version='1.0' encoding='UTF-8'?>
|
175
|
+
<KAF xml:lang="en">
|
176
|
+
<kafHeader>
|
177
|
+
<linguisticProcessors layer="text">
|
178
|
+
<lp timestamp="2013-04-11T09:21:29CEST" version="1.0" name="Open-nlp sentence splitter"/>
|
179
|
+
<lp timestamp="2013-04-11T09:21:29CEST" version="1.0" name="Open-nlp tokenizer"/>
|
180
|
+
</linguisticProcessors>
|
181
|
+
<linguisticProcessor layer="terms">
|
182
|
+
<lp timestamp="2013-04-11T09:23:08CEST" version="1.0" name="Basic_polarity_tagger_with_pos"/>
|
183
|
+
</linguisticProcessor>
|
184
|
+
<linguisticProcessor layer="term">
|
185
|
+
<lp timestamp="2013-04-11T09:23:07CEST" version="1.0" name="TreeTagger_from_kaf"/>
|
186
|
+
</linguisticProcessor>
|
187
|
+
</kafHeader>
|
188
|
+
<text>
|
189
|
+
<wf wid="w_1" sent="s_1">This</wf>
|
190
|
+
<wf wid="w_2" sent="s_1">is</wf>
|
191
|
+
<wf wid="w_3" sent="s_1">a</wf>
|
192
|
+
<wf wid="w_4" sent="s_1">very</wf>
|
193
|
+
<wf wid="w_5" sent="s_1">nice</wf>
|
194
|
+
<wf wid="w_6" sent="s_1">hotel</wf>
|
195
|
+
<wf wid="w_7" sent="s_1">in</wf>
|
196
|
+
<wf wid="w_8" sent="s_1">Amsterdam</wf>
|
197
|
+
</text>
|
198
|
+
<terms>
|
199
|
+
<term tid="t_1" lemma="this" morphofeat="DT" type="close" pos="D">
|
200
|
+
<span>
|
201
|
+
<target id="w_1"/>
|
202
|
+
</span>
|
203
|
+
</term>
|
204
|
+
<term tid="t_2" lemma="be" morphofeat="VBZ" type="open" pos="V">
|
205
|
+
<span>
|
206
|
+
<target id="w_2"/>
|
207
|
+
</span>
|
208
|
+
</term>
|
209
|
+
<term tid="t_3" lemma="a" morphofeat="DT" type="close" pos="D">
|
210
|
+
<span>
|
211
|
+
<target id="w_3"/>
|
212
|
+
</span>
|
213
|
+
</term>
|
214
|
+
<term tid="t_4" lemma="very" morphofeat="RB" type="open" pos="A">
|
215
|
+
<span>
|
216
|
+
<target id="w_4"/>
|
217
|
+
</span>
|
218
|
+
<sentiment sentiment_modifier="intensifier" resource="VUA_olery_lexicon_en_lmf"/>
|
219
|
+
</term>
|
220
|
+
<term tid="t_5" lemma="nice" morphofeat="JJ" type="open" pos="G">
|
221
|
+
<span>
|
222
|
+
<target id="w_5"/>
|
223
|
+
</span>
|
224
|
+
<sentiment polarity="positive" resource="VUA_olery_lexicon_en_lmf"/>
|
225
|
+
</term>
|
226
|
+
<term tid="t_6" lemma="hotel" morphofeat="NN" type="open" pos="N">
|
227
|
+
<span>
|
228
|
+
<target id="w_6"/>
|
229
|
+
</span>
|
230
|
+
</term>
|
231
|
+
<term tid="t_7" lemma="in" morphofeat="IN" type="close" pos="P">
|
232
|
+
<span>
|
233
|
+
<target id="w_7"/>
|
234
|
+
</span>
|
235
|
+
</term>
|
236
|
+
<term tid="t_8" lemma="Amsterdam" morphofeat="NP" type="open" pos="R">
|
237
|
+
<span>
|
238
|
+
<target id="w_8"/>
|
239
|
+
</span>
|
240
|
+
</term>
|
241
|
+
</terms>
|
242
|
+
<entities>
|
243
|
+
<entity eid="e15" type="location">
|
244
|
+
<references>
|
245
|
+
<span>
|
246
|
+
<!--Amsterdam -->
|
247
|
+
<target id="t_8" />
|
248
|
+
</span>
|
249
|
+
</references>
|
250
|
+
</entity>
|
251
|
+
</entities>
|
252
|
+
</KAF></pre>
|
253
|
+
|
254
|
+
<dt>callbacks</dt>
|
255
|
+
<dd>
|
256
|
+
You can provide a list of callback urls. If you provide callback urls
|
257
|
+
the Opinion detector will run as a background job and a callback
|
258
|
+
with the results will be performed (POST) to the first url in the callback
|
259
|
+
list. The other urls in callback list will be provided in the "callbacks"
|
260
|
+
argument.<br/><br/>
|
261
|
+
Using callback you can chain together several OpeNER webservices in
|
262
|
+
one call. The first, will call the second, which will call the third, etc.
|
263
|
+
See for more information the <a href="http://opener-project.github.io">
|
264
|
+
webservice documentation online</a>.
|
265
|
+
</dd>
|
266
|
+
<dt>error_callback</dt>
|
267
|
+
<dd>URL to notify if errors occur in the background process. The error
|
268
|
+
callback will do a POST with the error message in the 'error' field.</dd>
|
269
|
+
</dt>
|
270
|
+
|
271
|
+
|
272
|
+
|
273
|
+
</dl>
|
274
|
+
|
275
|
+
|
276
|
+
<p>
|
277
|
+
|
278
|
+
</p>
|
279
|
+
|
280
|
+
</body>
|
281
|
+
</html>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<link type="text/css" rel="stylesheet" charset="UTF-8" href="markdown.css"/>
|
5
|
+
<title>Language Detector Webservice</title>
|
6
|
+
</head>
|
7
|
+
<body>
|
8
|
+
<h1>Output URL</h1>
|
9
|
+
<p>
|
10
|
+
When ready, you can view the result
|
11
|
+
<a href=<%= output_url %>>here</a>
|
12
|
+
</p>
|
13
|
+
|
14
|
+
</body>
|
15
|
+
</html>
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require File.expand_path('../lib/opener/opinion_detector/version', __FILE__)
|
2
|
+
|
3
|
+
Gem::Specification.new do |gem|
|
4
|
+
gem.name = 'opener-opinion-detector'
|
5
|
+
gem.version = Opener::OpinionDetector::VERSION
|
6
|
+
gem.authors = ['development@olery.com']
|
7
|
+
gem.summary = 'Gem that wraps up the different existing opinion detectors'
|
8
|
+
gem.description = gem.summary
|
9
|
+
gem.homepage = 'http://opener-project.github.com/'
|
10
|
+
gem.has_rdoc = "yard"
|
11
|
+
gem.required_ruby_version = ">= 1.9.2"
|
12
|
+
|
13
|
+
gem.files = Dir.glob([
|
14
|
+
'lib/**/*',
|
15
|
+
'config.ru',
|
16
|
+
'*.gemspec',
|
17
|
+
'README.md'
|
18
|
+
]).select { |file| File.file?(file) }
|
19
|
+
|
20
|
+
gem.executables = Dir.glob('bin/*').map { |file| File.basename(file) }
|
21
|
+
|
22
|
+
gem.add_dependency 'opener-opinion-detector-base'
|
23
|
+
gem.add_dependency 'nokogiri'
|
24
|
+
gem.add_dependency 'sinatra', '~>1.4.2'
|
25
|
+
gem.add_dependency 'httpclient'
|
26
|
+
gem.add_dependency 'opener-webservice'
|
27
|
+
|
28
|
+
gem.add_development_dependency 'rspec'
|
29
|
+
gem.add_development_dependency 'cucumber'
|
30
|
+
gem.add_development_dependency 'pry'
|
31
|
+
gem.add_development_dependency 'rake'
|
32
|
+
end
|
33
|
+
|
metadata
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: opener-opinion-detector
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- development@olery.com
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-05-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: opener-opinion-detector-base
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: nokogiri
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: sinatra
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.4.2
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.4.2
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: httpclient
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: opener-webservice
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: cucumber
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: pry
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rake
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
description: Gem that wraps up the different existing opinion detectors
|
140
|
+
email:
|
141
|
+
executables:
|
142
|
+
- opinion-detector-server
|
143
|
+
- opinion-detector
|
144
|
+
extensions: []
|
145
|
+
extra_rdoc_files: []
|
146
|
+
files:
|
147
|
+
- README.md
|
148
|
+
- bin/opinion-detector
|
149
|
+
- bin/opinion-detector-server
|
150
|
+
- config.ru
|
151
|
+
- lib/opener/opinion_detector.rb
|
152
|
+
- lib/opener/opinion_detector/cli.rb
|
153
|
+
- lib/opener/opinion_detector/public/markdown.css
|
154
|
+
- lib/opener/opinion_detector/server.rb
|
155
|
+
- lib/opener/opinion_detector/version.rb
|
156
|
+
- lib/opener/opinion_detector/views/index.erb
|
157
|
+
- lib/opener/opinion_detector/views/result.erb
|
158
|
+
- opener-opinion-detector.gemspec
|
159
|
+
homepage: http://opener-project.github.com/
|
160
|
+
licenses: []
|
161
|
+
metadata: {}
|
162
|
+
post_install_message:
|
163
|
+
rdoc_options: []
|
164
|
+
require_paths:
|
165
|
+
- lib
|
166
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
167
|
+
requirements:
|
168
|
+
- - ">="
|
169
|
+
- !ruby/object:Gem::Version
|
170
|
+
version: 1.9.2
|
171
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
172
|
+
requirements:
|
173
|
+
- - ">="
|
174
|
+
- !ruby/object:Gem::Version
|
175
|
+
version: '0'
|
176
|
+
requirements: []
|
177
|
+
rubyforge_project:
|
178
|
+
rubygems_version: 2.2.2
|
179
|
+
signing_key:
|
180
|
+
specification_version: 4
|
181
|
+
summary: Gem that wraps up the different existing opinion detectors
|
182
|
+
test_files: []
|
183
|
+
has_rdoc: yard
|