zemanta_client 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/.gitignore +17 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +64 -0
  5. data/Rakefile +1 -0
  6. data/lib/zemanta.rb +39 -0
  7. data/lib/zemanta/cache.rb +7 -0
  8. data/lib/zemanta/cache/disk.rb +21 -0
  9. data/lib/zemanta/configuration.rb +32 -0
  10. data/lib/zemanta/configuration/null_storage.rb +12 -0
  11. data/lib/zemanta/fetcher.rb +36 -0
  12. data/lib/zemanta/fetcher/cache.rb +33 -0
  13. data/lib/zemanta/fetcher/cache/key.rb +27 -0
  14. data/lib/zemanta/fetcher/cache/null_response.rb +11 -0
  15. data/lib/zemanta/fetcher/cache/response.rb +16 -0
  16. data/lib/zemanta/fetcher/web.rb +35 -0
  17. data/lib/zemanta/markup.rb +14 -0
  18. data/lib/zemanta/markup/link.rb +23 -0
  19. data/lib/zemanta/markup/link/target.rb +15 -0
  20. data/lib/zemanta/version.rb +3 -0
  21. data/spec/fixtures/zemanta/full_response.json +75 -0
  22. data/spec/fixtures/zemanta/link.json +15 -0
  23. data/spec/fixtures/zemanta/markup.json +20 -0
  24. data/spec/fixtures/zemanta/target.json +5 -0
  25. data/spec/spec_helper.rb +43 -0
  26. data/spec/zemanta/cache/disk_spec.rb +53 -0
  27. data/spec/zemanta/configuration/null_storage_spec.rb +13 -0
  28. data/spec/zemanta/configuration_spec.rb +63 -0
  29. data/spec/zemanta/fetcher/cache/key_spec.rb +17 -0
  30. data/spec/zemanta/fetcher/cache/null_response_spec.rb +7 -0
  31. data/spec/zemanta/fetcher/cache/response_spec.rb +8 -0
  32. data/spec/zemanta/fetcher/cache_spec.rb +31 -0
  33. data/spec/zemanta/fetcher/web_spec.rb +8 -0
  34. data/spec/zemanta/fetcher_spec.rb +16 -0
  35. data/spec/zemanta/integration/correct_response_spec.rb +57 -0
  36. data/spec/zemanta/integration/incorrect_api_key_spec.rb +11 -0
  37. data/spec/zemanta/markup/link/target_spec.rb +19 -0
  38. data/spec/zemanta/markup/link_spec.rb +48 -0
  39. data/spec/zemanta/markup_spec.rb +16 -0
  40. data/spec/zemanta_spec.rb +19 -0
  41. data/zemanta.gemspec +25 -0
  42. metadata +171 -0
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in zemanta.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 TODO: Write your name
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # Zemanta
2
+
3
+ This is a ruby client to awesome Zemanta app. At this point it only supports suggest_markup method and is tested on ruby 1.9.3.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'zemanta_client'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install zemanta_client
18
+
19
+ ## Usage
20
+
21
+ You need to set api_key to use the client. If you won't do that, gem will raise an error. There are 2 ways:
22
+ 1. Environment variable
23
+ - Set ZEMANTA_KEY key in you environment variables and gem will use it
24
+
25
+ 2. Configuration
26
+ - You can set your api_key in configuration block like this:
27
+ - Zemanta.configure { |c| c.api_key = 'your_api_key' }
28
+
29
+ After your api_key has been set, all you need to do is:
30
+
31
+ Zemanta.new("Text you want to send to Zemanta").suggest_markup
32
+
33
+ And you will be returned Markup object or error will be raised if Zemanta returns one.
34
+
35
+ ## Configuration
36
+
37
+ There are several configuration options you can set:
38
+
39
+ Zemanta.configure do |config|
40
+ You can pass a hash of custom options that will be passed into each request. It's empty by default.
41
+ config.custom_request_opts = {}
42
+
43
+ Zemanta supports various response formats. However, this client works only with json, so changing this would be rather bad idea.
44
+ config.format = "json"
45
+
46
+ This client supports caching, details below. Default is no caching.
47
+ config.cache_store = Zemanta::Configuration::NullStorage
48
+
49
+ You can pass api_key to zemanta, as described above.
50
+ config.api_key = "yourapikeyhere"
51
+ end
52
+
53
+ ## Caching
54
+ By default there is no caching. You can pass any cache store to config.cache_store in configuration.
55
+ The only expectation is that it answers to [] and []= methods. For example, you can pass ruby hash or Cache::Disk.new
56
+ object to use simple file system storage.
57
+
58
+ ## Contributing
59
+
60
+ 1. Fork it
61
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
62
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
63
+ 4. Push to the branch (`git push origin my-new-feature`)
64
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/lib/zemanta.rb ADDED
@@ -0,0 +1,39 @@
1
+ require 'active_support/dependencies/autoload'
2
+ require 'typhoeus'
3
+ require 'json'
4
+ require 'digest/md5'
5
+
6
+ class Zemanta
7
+ extend ActiveSupport::Autoload
8
+
9
+ autoload :Cache
10
+ autoload :Configuration
11
+ autoload :Fetcher
12
+ autoload :Markup
13
+
14
+ def initialize(text)
15
+ @text = text
16
+ end
17
+
18
+ def suggest_markup(opts = {})
19
+ Markup.new(suggest_markup_request(opts))
20
+ end
21
+
22
+ def self.configure
23
+ yield config
24
+ end
25
+
26
+ def self.config
27
+ @configuration ||= Configuration.new
28
+ end
29
+
30
+ private
31
+
32
+ def suggest_markup_request(opts)
33
+ @response ||= request({ text: @text, method: "zemanta.suggest_markup" }.merge(opts))['markup']
34
+ end
35
+
36
+ def request(opts)
37
+ Fetcher.new(opts).post
38
+ end
39
+ end
@@ -0,0 +1,7 @@
1
+ class Zemanta
2
+ module Cache
3
+ extend ActiveSupport::Autoload
4
+
5
+ autoload :Disk
6
+ end
7
+ end
@@ -0,0 +1,21 @@
1
+ class Zemanta
2
+ module Cache
3
+ class Disk
4
+ attr_accessor :db
5
+
6
+ def initialize(directory='tmp/db')
7
+ @db = Pathname.new(directory)
8
+ @db.mkpath
9
+ end
10
+
11
+ def [](key)
12
+ file = @db.join(key)
13
+ file.read if file.exist?
14
+ end
15
+
16
+ def []=(key,value)
17
+ @db.join(key).open('w') {|f| f.write(value.to_s)}
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,32 @@
1
+ class Zemanta
2
+ class Configuration
3
+ extend ActiveSupport::Autoload
4
+
5
+ autoload :NullStorage
6
+
7
+ attr_accessor :custom_request_opts, :format, :api_key, :cache_storage
8
+
9
+ def initialize
10
+ @custom_request_opts = {}
11
+ @format = "json"
12
+ @cache_storage = NullStorage.new
13
+ end
14
+
15
+ def request_opts
16
+ {
17
+ api_key: actual_api_key,
18
+ format: @format
19
+ }.merge(@custom_request_opts)
20
+ end
21
+
22
+ def end_point
23
+ "http://api.zemanta.com/services/rest/0.0/"
24
+ end
25
+
26
+ private
27
+
28
+ def actual_api_key
29
+ @api_key || ENV["ZEMANTA_KEY"] or raise "You need to specify ZEMANTA_KEY in your environment or set api_key in your config"
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,12 @@
1
+ class Zemanta
2
+ class Configuration
3
+ class NullStorage
4
+ def [](key)
5
+ nil
6
+ end
7
+
8
+ def []=(key,value)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,36 @@
1
+ class Zemanta
2
+ class Fetcher
3
+ extend ActiveSupport::Autoload
4
+
5
+ autoload :Cache
6
+ autoload :Web
7
+
8
+ def initialize(opts = {})
9
+ @opts = opts
10
+ end
11
+
12
+ def post
13
+ @response = cache.fetch || web.fetch
14
+ cache.save(@response)
15
+ parse(@response)
16
+ end
17
+
18
+ private
19
+
20
+ def cache
21
+ @cache ||= Cache.new(@opts)
22
+ end
23
+
24
+ def web
25
+ Web.new(request_opts)
26
+ end
27
+
28
+ def parse(data)
29
+ JSON.parse(data)
30
+ end
31
+
32
+ def request_opts
33
+ @request_opts ||= Zemanta.config.request_opts.merge(@opts)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,33 @@
1
+ class Zemanta
2
+ class Fetcher
3
+ class Cache
4
+ extend ActiveSupport::Autoload
5
+
6
+ autoload :NullResponse
7
+ autoload :Response
8
+ autoload :Key
9
+
10
+ def initialize(opts = {})
11
+ @key = Key.new(opts).to_s
12
+ end
13
+
14
+ def fetch
15
+ fetch_from_storage(@key).to_s
16
+ end
17
+
18
+ def save(response)
19
+ storage[@key] = Response.new(response) unless storage[@key]
20
+ end
21
+
22
+ private
23
+
24
+ def storage
25
+ Zemanta.config.cache_storage
26
+ end
27
+
28
+ def fetch_from_storage(opts)
29
+ storage[@key] || NullResponse.new
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,27 @@
1
+ class Zemanta
2
+ class Fetcher
3
+ class Cache
4
+ class Key
5
+ def initialize(value)
6
+ @value = value
7
+ end
8
+
9
+ def to_s
10
+ if @value.is_a?(String)
11
+ digest(@value)
12
+ elsif @value.is_a?(Hash)
13
+ digest(@value.sort.to_s)
14
+ else
15
+ raise "You are trying to use #{@value.class} as cache key. Only Strings and Hashes are supported."
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def digest(value)
22
+ Digest::MD5.hexdigest(value)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,11 @@
1
+ class Zemanta
2
+ class Fetcher
3
+ class Cache
4
+ class NullResponse
5
+ def to_s
6
+ nil
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,16 @@
1
+ class Zemanta
2
+ class Fetcher
3
+ class Cache
4
+ class Response
5
+ def initialize(data)
6
+ @data = data
7
+ @created_at = Time.now
8
+ end
9
+
10
+ def to_s
11
+ @data
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,35 @@
1
+ class Zemanta
2
+ class Fetcher
3
+ class Web
4
+ def initialize(opts = {})
5
+ @opts = opts
6
+ end
7
+
8
+ def fetch
9
+ if http_fetch == zemanta_error_response
10
+ raise_api_key_exception!
11
+ else
12
+ http_fetch
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def http_fetch
19
+ @response ||= Typhoeus.post(url, params: @opts).response_body
20
+ end
21
+
22
+ def zemanta_error_response
23
+ '<h1>403 Developer Inactive</h1>'
24
+ end
25
+
26
+ def raise_api_key_exception!
27
+ raise "Zemanta returned '#{zemanta_error_response}' exception. Quite possibly you passed incorrect api_key."
28
+ end
29
+
30
+ def url
31
+ Zemanta.config.end_point
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,14 @@
1
+ class Zemanta
2
+ class Markup
3
+ extend ActiveSupport::Autoload
4
+
5
+ autoload :Link
6
+
7
+ attr_reader :text, :links
8
+
9
+ def initialize(opts = {})
10
+ @text = opts["text"]
11
+ @links = opts["links"].map{ |link| Link.new(link) }
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,23 @@
1
+ class Zemanta
2
+ class Markup
3
+ class Link
4
+ extend ActiveSupport::Autoload
5
+
6
+ autoload :Target
7
+
8
+ attr_reader :relevance, :confidence, :entity_type, :target, :anchor
9
+
10
+ def initialize(opts = {})
11
+ @relevance = opts["relevance"]
12
+ @confidence = opts["confidence"]
13
+ @entity_type = opts["entity_type"]
14
+ @target = opts["target"].map{ |opts| Target.new(opts) }
15
+ @anchor = opts["anchor"]
16
+ end
17
+
18
+ def above?(relevance, confidence)
19
+ @relevance >= relevance and @confidence >= confidence
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,15 @@
1
+ class Zemanta
2
+ class Markup
3
+ class Link
4
+ class Target
5
+ attr_reader :url, :type, :title
6
+
7
+ def initialize(opts = {})
8
+ @url = opts["url"]
9
+ @type = opts["type"]
10
+ @title = opts["title"]
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ class Zemanta
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,75 @@
1
+ {
2
+ "status": "ok",
3
+ "articles": [
4
+ {
5
+ "confidence": 0.00114,
6
+ "published_datetime": "2013-02-23T06:39:14Z",
7
+ "title": "Tiananmen Square- Forbidden City- Summer Palace - Beijing, China",
8
+ "url": "http://blog.travelpod.com/travel-blog-entries/peregrinations/1/1315695831/tpod.html",
9
+ "retweets": 0,
10
+ "text_preview": "Tiananmen Square- Forbidden City- Summer Palace - Beijing, China\nBeijing, China\nThis was our last day of touring and it was by far the most arduous of the whole trip. I have no idea how anyone can do this in the heat and humidity of July and August. It was just the end of May and the heat did me in. Even though our guide took a very leisurely pace...",
11
+ "article_id": 147457867,
12
+ "zemified": 0
13
+ }
14
+ ],
15
+ "markup": {
16
+ "text": "",
17
+ "links": [
18
+ {
19
+ "relevance": 0.8093,
20
+ "confidence": 0.873863,
21
+ "entity_type": [
22
+ "/location/location"
23
+ ],
24
+ "target": [
25
+ {
26
+ "url": "http://maps.google.com/maps?ll=27.2359361111,100.132480556&spn=0.01,0.01&q=27.2359361111,100.132480556 (Tiger%20Leaping%20Gorge)&t=h",
27
+ "type": "geolocation",
28
+ "title": "Tiger Leaping Gorge"
29
+ }
30
+ ],
31
+ "anchor": "Tiger Leaping Gorge"
32
+ }
33
+ ]
34
+ },
35
+ "images": [
36
+ {
37
+ "url_m_h": 240,
38
+ "confidence": 0.5,
39
+ "url_s_h": 75,
40
+ "attribution": "Naxi Horseman (Photo credit: <a href=\"http://www.flickr.com/photos/85904220@N00/3182514166\">Renato @ Mainland China</a>)",
41
+ "description": "Naxi Horseman",
42
+ "license": "License CreativeCommons NonCommercial NoDerivs",
43
+ "url_l_w": 365,
44
+ "url_s": "http://farm4.static.flickr.com/3115/3182514166_186de79cab_s.jpg",
45
+ "source_url": "http://www.flickr.com/photos/85904220@N00/3182514166",
46
+ "url_m": "http://farm4.static.flickr.com/3115/3182514166_186de79cab_m.jpg",
47
+ "url_l": "http://farm4.static.flickr.com/3115/3182514166_186de79cab.jpg",
48
+ "url_l_h": 500,
49
+ "url_s_w": 75,
50
+ "url_m_w": 175
51
+ }
52
+ ],
53
+ "signature": "<div class=\"zemanta-pixie\"><a class=\"zemanta-pixie-a\" href=\"http://www.zemanta.com/?px\" title=\"Enhanced by Zemanta\"><img class=\"zemanta-pixie-img\" src=\"http://img.zemanta.com/zemified_e.png?x-id=27556886-7e10-4b64-8bff-9fa4352fd524\" alt=\"Enhanced by Zemanta\" /></a></div>",
54
+ "keywords": [
55
+ {
56
+ "confidence": 0.267918,
57
+ "scheme": "general",
58
+ "name": "Beijing"
59
+ }
60
+ ],
61
+ "rid": "27556886-7e10-4b64-8bff-9fa4352fd524",
62
+ "categories": [],
63
+ "rich_objects": [
64
+ {
65
+ "title": "Tiananmen Square",
66
+ "url": "http://maps.google.com/maps?ll=39.9033333333,116.391666667&spn=0.01,0.01&q=39.9033333333,116.391666667 (Tiananmen%20Square)&t=h",
67
+ "thumbnail_width": 75,
68
+ "height": 250,
69
+ "width": 300,
70
+ "html": "<iframe width=\"300\" height=\"250\" frameborder=\"0\" scrolling=\"no\" marginheight=\"0\" marginwidth=\"0\" src=\"http://maps.google.com/?ie=UTF8&amp;center=39.9033333333,116.391666667&amp;spn=0.01,0.01&amp;q=39.9033333333,116.391666667 (Tiananmen%20Square)&amp;t=h&amp;output=embed&amp;sensor=false&amp;s=AARTsJqzARj-Z8VnW5pkPMLMmZbqrJcYpw\"></iframe><br/><small><a href=\"http://maps.google.com/?ie=UTF8&amp;center=39.9033333333,116.391666667&amp;spn=0.01,0.01&amp;q=39.9033333333,116.391666667 (Tiananmen%20Square)&amp;t=h&amp;source=embed&amp;sensor=false\" style=\"color:#0000FF;text-align:left\">View Larger Map</a></small>",
71
+ "thumbnail_height": 75,
72
+ "thumbnail_url": "http://maps.google.com/staticmap?size=300x250&sensor=false&center=39.9033333333,116.391666667&zoom=15"
73
+ }
74
+ ]
75
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "relevance": 0.8093,
3
+ "confidence": 0.873863,
4
+ "entity_type": [
5
+ "/location/location"
6
+ ],
7
+ "target": [
8
+ {
9
+ "url": "www.this.is.an/url",
10
+ "type": "geolocation",
11
+ "title": "Tiger Leaping Gorge"
12
+ }
13
+ ],
14
+ "anchor": "Tiger Leaping Gorge"
15
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "text": "text",
3
+ "links": [
4
+ {
5
+ "relevance": 0.8093,
6
+ "confidence": 0.873863,
7
+ "entity_type": [
8
+ "/location/location"
9
+ ],
10
+ "target": [
11
+ {
12
+ "url": "www.this.is.an/url",
13
+ "type": "geolocation",
14
+ "title": "Tiger Leaping Gorge"
15
+ }
16
+ ],
17
+ "anchor": "Tiger Leaping Gorge"
18
+ }
19
+ ]
20
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "url": "www.this.is.an/url",
3
+ "type": "geolocation",
4
+ "title": "Tiger Leaping Gorge"
5
+ }
@@ -0,0 +1,43 @@
1
+ require 'zemanta'
2
+ require 'webmock/rspec'
3
+
4
+ Zemanta.configure do |c|
5
+ c.api_key = 'fake_key'
6
+ end
7
+ # This file was generated by the `rspec --init` command. Conventionally, all
8
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
9
+ # Require this file using `require "spec_helper"` to ensure that it is only
10
+ # loaded once.
11
+ #
12
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
13
+ RSpec.configure do |config|
14
+ config.treat_symbols_as_metadata_keys_with_true_values = true
15
+ config.run_all_when_everything_filtered = true
16
+ config.filter_run :focus
17
+
18
+ # Run specs in random order to surface order dependencies. If you find an
19
+ # order dependency and want to debug it, you can fix the order by providing
20
+ # the seed, which is printed after each run.
21
+ # --seed 1234
22
+ config.order = 'random'
23
+ end
24
+
25
+ def fixture(path)
26
+ JSON.parse(File.read("spec/fixtures/zemanta/#{path}.json"))
27
+ end
28
+
29
+ def stub_zemanta_success!
30
+ stub_request(:post, /api.zemanta.com/).
31
+ to_return(:status => 200, :body => "{\"response\":\"zemanta_response\"}").times(1).then.
32
+ to_return(:status => 404)
33
+ end
34
+
35
+ def stub_zemanta_full!
36
+ stub_request(:post, /api.zemanta.com/).
37
+ to_return(:status => 200, :body => {markup: fixture("markup")}.to_json)
38
+ end
39
+
40
+ def stub_zemanta_exception!
41
+ stub_request(:post, /api.zemanta.com/).
42
+ to_return(:status => 200, :body => '<h1>403 Developer Inactive</h1>')
43
+ end
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zemanta::Cache::Disk do
4
+ let(:cache) { Zemanta::Cache::Disk }
5
+ let(:storage) { cache.new }
6
+
7
+ describe "#initialize" do
8
+ it "creates directory to store files if one doesnt exist" do
9
+ temp_dir = Pathname.new('spec/temp_dir')
10
+ temp_dir.delete if temp_dir.exist?
11
+ temp_dir.should_not exist
12
+
13
+ cache.new(temp_dir)
14
+ temp_dir.should exist
15
+ temp_dir.delete
16
+ end
17
+
18
+ it "uses tmp/db as default directory" do
19
+ storage.db.should == Pathname.new('tmp/db')
20
+ end
21
+ end
22
+
23
+ describe "#[key]" do
24
+ it "returns nil if key doesnt exist" do
25
+ storage['non-existing-key'].should be_nil
26
+ end
27
+
28
+ it "returns stored value if the key exists" do
29
+ value = "string data"
30
+ storage['key'] = value
31
+ storage['key'].should == value
32
+ end
33
+ end
34
+
35
+ describe "#[key]=" do
36
+ let(:key) { 'some-key' }
37
+ let(:value) { 'text-value' }
38
+
39
+ it "creates new file for specified key" do
40
+ Pathname.new(storage.db.join(key)).delete
41
+ Pathname.new(storage.db.join(key)).should_not exist
42
+
43
+ storage[key] = value
44
+ Pathname.new(storage.db.join(key)).should exist
45
+ end
46
+
47
+ it "overwrites existing file for specified key" do
48
+ storage[key] = value
49
+ storage[key] = "new value"
50
+ storage[key].should == "new value"
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zemanta::Fetcher::Web do
4
+ subject { Zemanta::Configuration::NullStorage.new }
5
+
6
+ it "returns nil on #[]" do
7
+ subject[:key].should be_nil
8
+ end
9
+
10
+ it "responds to #save" do
11
+ subject.should respond_to :[]=
12
+ end
13
+ end
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zemanta::Configuration do
4
+ subject { Zemanta::Configuration.new }
5
+
6
+ describe "getter" do
7
+ it "gets custom_request_opts" do
8
+ subject.custom_request_opts.should == {}
9
+ end
10
+
11
+ it "gets format" do
12
+ subject.format.should == "json"
13
+ end
14
+
15
+ it "gets api_key" do
16
+ subject.api_key.should == nil
17
+ end
18
+
19
+ it "gets cache_storage" do
20
+ subject.cache_storage.should be_a Zemanta::Configuration::NullStorage
21
+ end
22
+ end
23
+
24
+ describe "setter" do
25
+ it "sets custom_request_opts" do
26
+ subject.custom_request_opts = {target_types: "geolocation"}
27
+ subject.custom_request_opts.should == {target_types: "geolocation"}
28
+ end
29
+
30
+ it "sets format" do
31
+ subject.format = "xml"
32
+ subject.format.should == "xml"
33
+ end
34
+
35
+ it "sets api_key" do
36
+ subject.api_key = "key"
37
+ subject.api_key.should == "key"
38
+ end
39
+
40
+ it "sets cache_storage" do
41
+ subject.cache_storage = {}
42
+ subject.cache_storage.should == {}
43
+ end
44
+ end
45
+
46
+ it "knows the end_point" do
47
+ subject.end_point.should == "http://api.zemanta.com/services/rest/0.0/"
48
+ end
49
+
50
+ it "can build the request_opts" do
51
+ subject.stub(:actual_api_key).and_return("api_key")
52
+ subject.request_opts.should == {
53
+ api_key: "api_key",
54
+ format: "json"
55
+ }
56
+ end
57
+
58
+ it "custom_request_opts into request_opts" do
59
+ subject.stub(:actual_api_key).and_return("api_key")
60
+ subject.custom_request_opts = {target_types: "geolocation"}
61
+ subject.request_opts[:target_types].should == "geolocation"
62
+ end
63
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zemanta::Fetcher::Cache::Key do
4
+ it "returns string by #to_s, given string" do
5
+ Zemanta::Fetcher::Cache::Key.new("").to_s.should be_a String
6
+ end
7
+
8
+ it "returns string by #to_s, given hash" do
9
+ Zemanta::Fetcher::Cache::Key.new({}).to_s.should be_a String
10
+ end
11
+
12
+ it "creates identical values for hashes with different order" do
13
+ key_1 = Zemanta::Fetcher::Cache::Key.new({key: "value", awesomeness: "high"})
14
+ key_2 = Zemanta::Fetcher::Cache::Key.new({awesomeness: "high", key: "value"})
15
+ key_1.to_s.should == key_2.to_s
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zemanta::Fetcher::Cache::NullResponse do
4
+ it "returns nil by #to_s" do
5
+ Zemanta::Fetcher::Cache::NullResponse.new.to_s.should be_nil
6
+ end
7
+ end
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zemanta::Fetcher::Cache::Response do
4
+ it "returns saved data by #to_s" do
5
+ response = Zemanta::Fetcher::Cache::Response.new("String of data")
6
+ response.to_s.should == "String of data"
7
+ end
8
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zemanta::Fetcher::Cache do
4
+ describe "for set storage" do
5
+ before :each do
6
+ Zemanta.configure { |config| config.cache_storage = {} }
7
+ Zemanta::Fetcher::Cache.new("key").save("test data")
8
+ end
9
+
10
+ after :all do
11
+ Zemanta.configure { |config| config.cache_storage = Zemanta::Configuration::NullStorage.new }
12
+ end
13
+
14
+ it "saves the data to cache if it's saved first time" do
15
+ Zemanta.config.cache_storage.size.should == 1
16
+ end
17
+
18
+ it "doesn't save the data if same key was used before" do
19
+ Zemanta::Fetcher::Cache.new("key").save("test data")
20
+ Zemanta.config.cache_storage.size.should == 1
21
+ end
22
+
23
+ it "fetch returns nil if no key in cache" do
24
+ Zemanta::Fetcher::Cache.new("another_key").fetch.should be_nil
25
+ end
26
+
27
+ it "fetch returns the value data if key is present" do
28
+ Zemanta::Fetcher::Cache.new("key").fetch.should == "test data"
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zemanta::Fetcher::Web do
4
+ it "delegates to Typhoeus on #fetch" do
5
+ stub_zemanta_success!
6
+ Zemanta::Fetcher::Web.new.fetch.should == "{\"response\":\"zemanta_response\"}"
7
+ end
8
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zemanta::Fetcher do
4
+ it "returns the value in cache, if there is one" do
5
+ Zemanta.configure { |config| config.cache_storage = {} }
6
+ stub_zemanta_success!
7
+ subject.post
8
+ subject.post.should == {"response"=>"zemanta_response"}
9
+ Zemanta.configure { |config| config.cache_storage = Zemanta::Configuration::NullStorage.new }
10
+ end
11
+
12
+ it "returns the value in web, if there is no cache" do
13
+ stub_zemanta_success!
14
+ subject.post.should == {"response"=>"zemanta_response"}
15
+ end
16
+ end
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+
3
+ describe "suggest_markup" do
4
+ before(:each) do
5
+ stub_zemanta_full!
6
+ end
7
+
8
+ let(:markup) { Zemanta.new("some text").suggest_markup }
9
+
10
+ it "responds to #text" do
11
+ markup.text.should == "text"
12
+ end
13
+
14
+ it "responds to #links" do
15
+ markup.links.should be_a Array
16
+ end
17
+
18
+ describe ".links.first" do
19
+ let(:link) { markup.links.first }
20
+
21
+ it "responds to #relevance" do
22
+ link.relevance.should == 0.8093
23
+ end
24
+
25
+ it "responds to #confidence" do
26
+ link.confidence.should == 0.873863
27
+ end
28
+
29
+ it "responds to #entity_type" do
30
+ link.entity_type.should == ["/location/location"]
31
+ end
32
+
33
+ it "responds to #target" do
34
+ link.target.should be_a Array
35
+ end
36
+
37
+ it "responds to #anchor" do
38
+ link.anchor.should == "Tiger Leaping Gorge"
39
+ end
40
+
41
+ describe ".target.first" do
42
+ let(:target) { link.target.first }
43
+
44
+ it "answers to #url" do
45
+ target.url.should == "www.this.is.an/url"
46
+ end
47
+
48
+ it "answers to #type" do
49
+ target.type.should == "geolocation"
50
+ end
51
+
52
+ it "answers to #title" do
53
+ target.title.should == "Tiger Leaping Gorge"
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,11 @@
1
+
2
+ require 'spec_helper'
3
+
4
+ describe "incorrect api key" do
5
+ let(:markup) { Zemanta.new("some text").suggest_markup }
6
+
7
+ it "raises exception when 403 error returned" do
8
+ stub_zemanta_exception!
9
+ expect { markup }.to raise_error("Zemanta returned '<h1>403 Developer Inactive</h1>' exception. Quite possibly you passed incorrect api_key.")
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zemanta::Markup::Link::Target do
4
+ describe "getter" do
5
+ subject { Zemanta::Markup::Link::Target.new(fixture("target")) }
6
+
7
+ it "for url works well" do
8
+ subject.url.should == "www.this.is.an/url"
9
+ end
10
+
11
+ it "for type works well" do
12
+ subject.type.should == "geolocation"
13
+ end
14
+
15
+ it "for target title works well" do
16
+ subject.title.should == "Tiger Leaping Gorge"
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zemanta::Markup::Link do
4
+ describe "getter" do
5
+ subject { Zemanta::Markup::Link.new(fixture("link")) }
6
+
7
+ describe "getter" do
8
+ it "for relevance works well" do
9
+ subject.relevance.should == 0.8093
10
+ end
11
+
12
+ it "for confidence works well" do
13
+ subject.confidence.should == 0.873863
14
+ end
15
+
16
+ it "for entity title works well" do
17
+ subject.entity_type.should == ["/location/location"]
18
+ end
19
+
20
+ it "for target returns array of targets" do
21
+ subject.target.should be_a Array
22
+ subject.target.first.should be_a Zemanta::Markup::Link::Target
23
+ end
24
+
25
+ it "for anchor works well" do
26
+ subject.anchor.should == "Tiger Leaping Gorge"
27
+ end
28
+ end
29
+
30
+ describe "above?" do
31
+ it "returns true if is above both relevance and confidence" do
32
+ subject.above?(0.5, 0.5).should == true
33
+ end
34
+
35
+ it "returns false if relevance is lower" do
36
+ subject.above?(0.9, 0.5).should == false
37
+ end
38
+
39
+ it "returns false if confidence is lower" do
40
+ subject.above?(0.5, 0.9).should == false
41
+ end
42
+
43
+ it "returns false if both confidence and relevance is lower" do
44
+ subject.above?(0.9, 0.9).should == false
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zemanta::Markup do
4
+ describe "getter" do
5
+ subject { Zemanta::Markup.new(fixture("markup")) }
6
+
7
+ it "for text works well" do
8
+ subject.text.should == "text"
9
+ end
10
+
11
+ it "for links returns array of links" do
12
+ subject.links.should be_a Array
13
+ subject.links.first.should be_a Zemanta::Markup::Link
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zemanta do
4
+ it "makes request with text and method params on #suggest_markup" do
5
+ context = Zemanta.new("This is a text")
6
+ context.stub(:suggest_markup_request) { fixture("markup") }
7
+ context.suggest_markup.should be_a Zemanta::Markup
8
+ end
9
+
10
+ it "returns Configuration instance on Zemanta.config" do
11
+ Zemanta.config.should be_a Zemanta::Configuration
12
+ end
13
+
14
+ it "passes Configuration instance to block on Zemanta.configure" do
15
+ Zemanta.configure do |config|
16
+ config.should be_a Zemanta::Configuration
17
+ end
18
+ end
19
+ end
data/zemanta.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'zemanta/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "zemanta_client"
8
+ gem.version = Zemanta::VERSION
9
+ gem.authors = ["Łukasz Strzebińczyk"]
10
+ gem.email = ["l.strzebinczyk@gorailsgo.com"]
11
+ gem.description = "This is a ruby client for Zemanta api."
12
+ gem.summary = "This is a ruby client for Zemanta api."
13
+ gem.homepage = ""
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency "typhoeus"
21
+ gem.add_dependency "activesupport"
22
+
23
+ gem.add_development_dependency "rspec"
24
+ gem.add_development_dependency "webmock"
25
+ end
metadata ADDED
@@ -0,0 +1,171 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: zemanta_client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Łukasz Strzebińczyk
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-04-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: typhoeus
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: activesupport
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: webmock
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ description: This is a ruby client for Zemanta api.
79
+ email:
80
+ - l.strzebinczyk@gorailsgo.com
81
+ executables: []
82
+ extensions: []
83
+ extra_rdoc_files: []
84
+ files:
85
+ - .gitignore
86
+ - Gemfile
87
+ - LICENSE.txt
88
+ - README.md
89
+ - Rakefile
90
+ - lib/zemanta.rb
91
+ - lib/zemanta/cache.rb
92
+ - lib/zemanta/cache/disk.rb
93
+ - lib/zemanta/configuration.rb
94
+ - lib/zemanta/configuration/null_storage.rb
95
+ - lib/zemanta/fetcher.rb
96
+ - lib/zemanta/fetcher/cache.rb
97
+ - lib/zemanta/fetcher/cache/key.rb
98
+ - lib/zemanta/fetcher/cache/null_response.rb
99
+ - lib/zemanta/fetcher/cache/response.rb
100
+ - lib/zemanta/fetcher/web.rb
101
+ - lib/zemanta/markup.rb
102
+ - lib/zemanta/markup/link.rb
103
+ - lib/zemanta/markup/link/target.rb
104
+ - lib/zemanta/version.rb
105
+ - spec/fixtures/zemanta/full_response.json
106
+ - spec/fixtures/zemanta/link.json
107
+ - spec/fixtures/zemanta/markup.json
108
+ - spec/fixtures/zemanta/target.json
109
+ - spec/spec_helper.rb
110
+ - spec/zemanta/cache/disk_spec.rb
111
+ - spec/zemanta/configuration/null_storage_spec.rb
112
+ - spec/zemanta/configuration_spec.rb
113
+ - spec/zemanta/fetcher/cache/key_spec.rb
114
+ - spec/zemanta/fetcher/cache/null_response_spec.rb
115
+ - spec/zemanta/fetcher/cache/response_spec.rb
116
+ - spec/zemanta/fetcher/cache_spec.rb
117
+ - spec/zemanta/fetcher/web_spec.rb
118
+ - spec/zemanta/fetcher_spec.rb
119
+ - spec/zemanta/integration/correct_response_spec.rb
120
+ - spec/zemanta/integration/incorrect_api_key_spec.rb
121
+ - spec/zemanta/markup/link/target_spec.rb
122
+ - spec/zemanta/markup/link_spec.rb
123
+ - spec/zemanta/markup_spec.rb
124
+ - spec/zemanta_spec.rb
125
+ - zemanta.gemspec
126
+ homepage: ''
127
+ licenses: []
128
+ post_install_message:
129
+ rdoc_options: []
130
+ require_paths:
131
+ - lib
132
+ required_ruby_version: !ruby/object:Gem::Requirement
133
+ none: false
134
+ requirements:
135
+ - - ! '>='
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ required_rubygems_version: !ruby/object:Gem::Requirement
139
+ none: false
140
+ requirements:
141
+ - - ! '>='
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
144
+ requirements: []
145
+ rubyforge_project:
146
+ rubygems_version: 1.8.24
147
+ signing_key:
148
+ specification_version: 3
149
+ summary: This is a ruby client for Zemanta api.
150
+ test_files:
151
+ - spec/fixtures/zemanta/full_response.json
152
+ - spec/fixtures/zemanta/link.json
153
+ - spec/fixtures/zemanta/markup.json
154
+ - spec/fixtures/zemanta/target.json
155
+ - spec/spec_helper.rb
156
+ - spec/zemanta/cache/disk_spec.rb
157
+ - spec/zemanta/configuration/null_storage_spec.rb
158
+ - spec/zemanta/configuration_spec.rb
159
+ - spec/zemanta/fetcher/cache/key_spec.rb
160
+ - spec/zemanta/fetcher/cache/null_response_spec.rb
161
+ - spec/zemanta/fetcher/cache/response_spec.rb
162
+ - spec/zemanta/fetcher/cache_spec.rb
163
+ - spec/zemanta/fetcher/web_spec.rb
164
+ - spec/zemanta/fetcher_spec.rb
165
+ - spec/zemanta/integration/correct_response_spec.rb
166
+ - spec/zemanta/integration/incorrect_api_key_spec.rb
167
+ - spec/zemanta/markup/link/target_spec.rb
168
+ - spec/zemanta/markup/link_spec.rb
169
+ - spec/zemanta/markup_spec.rb
170
+ - spec/zemanta_spec.rb
171
+ has_rdoc: