content-preview 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ .bundle/
2
+ log/*.log
3
+ pkg/
4
+ test/dummy/db/*.sqlite3
5
+ test/dummy/log/*.log
6
+ test/dummy/tmp/
7
+ test/dummy/.sass-cache
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem 'rspec'
data/Gemfile.lock ADDED
@@ -0,0 +1,39 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ content-preview (0.0.1)
5
+ json
6
+ nokogiri
7
+ rack-cors
8
+ rack-test
9
+ rake
10
+ thor
11
+
12
+ GEM
13
+ remote: http://rubygems.org/
14
+ specs:
15
+ diff-lcs (1.1.3)
16
+ json (1.7.5)
17
+ nokogiri (1.5.5)
18
+ rack (1.4.1)
19
+ rack-cors (0.2.7)
20
+ rack
21
+ rack-test (0.6.1)
22
+ rack (>= 1.0)
23
+ rake (0.9.2.2)
24
+ rspec (2.11.0)
25
+ rspec-core (~> 2.11.0)
26
+ rspec-expectations (~> 2.11.0)
27
+ rspec-mocks (~> 2.11.0)
28
+ rspec-core (2.11.1)
29
+ rspec-expectations (2.11.2)
30
+ diff-lcs (~> 1.1.3)
31
+ rspec-mocks (2.11.2)
32
+ thor (0.16.0)
33
+
34
+ PLATFORMS
35
+ ruby
36
+
37
+ DEPENDENCIES
38
+ content-preview!
39
+ rspec
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2012 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,13 @@
1
+ # Content Preview
2
+
3
+ This is a simple service for extracting media content from user posted text.
4
+ It can be used on any chunk of text to get the contained links or HTML and get the relevant media informations.
5
+ It'll behave like FB's content preview when you paste a link inside a message's text field.
6
+
7
+ ## Development
8
+
9
+ Currently under development ...
10
+
11
+ ## Licence
12
+
13
+ This software is licenced under the MIT licence
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env rake
2
+ require 'rspec/core/rake_task'
3
+
4
+ begin
5
+ require 'bundler/setup'
6
+ rescue LoadError
7
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
8
+ end
9
+
10
+ Bundler::GemHelper.install_tasks
11
+
12
+
13
+ RSpec::Core::RakeTask.new('spec')
14
+ task :default => :spec
15
+
16
+
data/bin/cp-server ADDED
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'thor'
4
+ require 'json'
5
+ require 'rack'
6
+ require 'yaml'
7
+
8
+ require 'content-preview/router'
9
+ require 'content-preview'
10
+
11
+ require 'rack'
12
+ require 'rack/cors'
13
+
14
+ class ContentPreviewServer < Thor
15
+
16
+ desc "start", "Starts a Rack server with the Rack::Handler and Port given as argument Defaults are Webrick and"
17
+ method_option :server, aliases: '-s', default: 'WEBrick', desc: "The Rack::Handler server to use (Webrick, Mongrel, Thin ...)"
18
+ method_option :port, aliases: '-p', default: '3210', desc: "The port to run the server on"
19
+ method_option :origin, aliases: '-o', default: '*', desc: "Allowed client origins"
20
+ def start
21
+ origin, port, server = options[:origin], options[:port], options[:server]
22
+
23
+ app = Rack::Builder.new do
24
+ use Rack::CommonLogger
25
+ use Rack::ShowExceptions
26
+ use Rack::Lint
27
+
28
+ use Rack::Cors do
29
+ allow do
30
+ origins origin
31
+ resource %r{/},
32
+ :headers => ['Origin', 'Accept', 'Content-Type'],
33
+ :methods => [:get, :post]
34
+ end
35
+ end
36
+
37
+ puts "Launch handler #{ server } on port #{ port }"
38
+ run ContentPreview::Router::Base
39
+
40
+ end
41
+
42
+ Rack::Handler.const_get(server).run(app, Host: '0.0.0.0', Port: port)
43
+ end
44
+ end
45
+
46
+ ContentPreviewServer.start
data/config.ru ADDED
@@ -0,0 +1,23 @@
1
+ require 'json'
2
+ require 'rack'
3
+ require 'yaml'
4
+ require 'rack/cors'
5
+
6
+ require 'content-preview/router'
7
+ require 'content-preview'
8
+
9
+ use ::Rack::CommonLogger
10
+ # use ::Rack::ShowExceptions
11
+ use ::Rack::Lint
12
+ #use Rack::Static, :urls => ["/static"]
13
+
14
+ use Rack::Cors do
15
+ allow do
16
+ origins 'http://localhost:3000'
17
+ resource %r{/},
18
+ :headers => ['Origin', 'Accept', 'Content-Type'],
19
+ :methods => [:get, :post]
20
+ end
21
+ end
22
+
23
+ run ContentPreview::Router::Base.new
@@ -0,0 +1,28 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+
3
+ # Maintain your gem's version:
4
+ require "content-preview/version"
5
+
6
+ # Describe your gem and declare its dependencies:
7
+ Gem::Specification.new do |s|
8
+ s.name = "content-preview"
9
+ s.version = ContentPreview::VERSION
10
+ s.authors = ["Glyph"]
11
+ s.email = ["vala@glyph.fr"]
12
+ s.homepage = "http://glyph.fr"
13
+ s.summary = "A simple service for getting URL page informations"
14
+ s.description = "A simple service for getting URL page informations"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.require_paths = ["lib"]
18
+ s.test_files = `git ls-files -- {spec}/*`.split("\n")
19
+ s.bindir = "bin"
20
+ s.executables = 'cp-server'
21
+
22
+ s.add_dependency 'thor'
23
+ s.add_dependency 'nokogiri'
24
+ s.add_dependency 'rake'
25
+ s.add_dependency 'rack-cors'
26
+ s.add_dependency 'rack-test'
27
+ s.add_dependency 'json'
28
+ end
@@ -0,0 +1,100 @@
1
+ class ContentPreview
2
+ constructor: () ->
3
+ @state = null
4
+
5
+ process: (str, callback) ->
6
+ url = @parseStr(str)
7
+ # Only request informations if we found an url
8
+ unless !url || url == @state
9
+ # Keep state for future preview requests
10
+ @state = url
11
+ @requestPreview(url, callback)
12
+
13
+ # Parsing
14
+ # Checking if str matches url regex
15
+ parseStr: (str) ->
16
+ urls = str.match(/(http\:\/\/[^\s]+)/)
17
+ # Return first occurence
18
+ urls[1] if urls
19
+
20
+ # Send request to remote service
21
+ requestPreview: (url, callback) ->
22
+ $.get $.fn.parseContentPreview.defaultOptions.url, { url: url }, ((resp) => @processResponse(resp, callback)), 'json'
23
+
24
+ # Response handling
25
+ processResponse: (resp, callback) ->
26
+ #callback(resp) if resp
27
+
28
+ # setting preview_* values to empty
29
+ $($.fn.parseContentPreview.defaultOptions.preview_title).text("")
30
+ $($.fn.parseContentPreview.defaultOptions.preview_description).text("")
31
+ $($.fn.parseContentPreview.defaultOptions.preview_image).empty()
32
+ $(".images").empty()
33
+ $($.fn.parseContentPreview.defaultOptions.form_hidden_inputs_name).empty()
34
+
35
+ if resp.title
36
+ $($.fn.parseContentPreview.defaultOptions.preview_title).text(resp.title)
37
+ $($.fn.parseContentPreview.defaultOptions.form_hidden_inputs_name).prepend('<input type="hidden" name="' + $.fn.parseContentPreview.defaultOptions.form_content_name + '[content_title]" value="' + resp.title + '"/>')
38
+
39
+ if resp.description
40
+ $($.fn.parseContentPreview.defaultOptions.preview_description).text(resp.description)
41
+ $($.fn.parseContentPreview.defaultOptions.form_hidden_inputs_name).prepend('<input type="hidden" name="' + $.fn.parseContentPreview.defaultOptions.form_content_name + '[content_description]" value="' + resp.description + '"/>')
42
+
43
+ if resp.image
44
+ $($.fn.parseContentPreview.defaultOptions.preview_image).prepend('<img width="200px" src="' + resp.image + '" />')
45
+ $($.fn.parseContentPreview.defaultOptions.form_hidden_inputs_name).prepend('<input type="hidden" name="' + $.fn.parseContentPreview.defaultOptions.form_content_name + '[content_image]" value="' + resp.image + '"/>')
46
+
47
+ if resp.images
48
+ resp.images.map (item) ->
49
+ unless (item.substr(0, 7) is "http://") || (item.substr(0, 2) is "//")
50
+ item = textarea.val() + item
51
+ $(".images").prepend('<img id="image_remote_preview_" src="' + item + '" />')
52
+
53
+ # show cross image if one the meta data is available
54
+ if resp.title or resp.description or resp.image or resp.images
55
+ $("#form-actions-cross").show()
56
+
57
+ $.fn.parseContentPreview = (str, callback) ->
58
+ this.each ->
59
+ # Get preview object or build a new if none exist
60
+ # preview = $(this).data('content-preview')
61
+
62
+ preview = new ContentPreview()
63
+ # Process str
64
+ preview.process str, callback
65
+
66
+ # default options
67
+ $.fn.parseContentPreview.defaultOptions = {
68
+ url: 'http://def.rs.af.cm',
69
+ form_content_name: 'post',
70
+ form_hidden_inputs_name: '.hidden_inputs',
71
+ preview_title: '#preview-title',
72
+ preview_description: '#preview-description',
73
+ preview_image: '#preview-image'
74
+ };
75
+
76
+ # method to select image from many images and prepend it to the form_hidden_inputs_name
77
+ preview_select_image = (image) ->
78
+ if $("input[name='" + $.fn.parseContentPreview.defaultOptions.form_content_name + "[content_image]']").length > 0
79
+ $("input[name='" + $.fn.parseContentPreview.defaultOptions.form_content_name + "[content_image]']").attr "value", image
80
+ else
81
+ $($.fn.parseContentPreview.defaultOptions.form_hidden_inputs_name).prepend "<input type='hidden' name='" + $.fn.parseContentPreview.defaultOptions.form_content_name + "[content_image]' value='" + image + "'/>"
82
+
83
+ $ ->
84
+ $("img[id='image_remote_preview_']").click (e) ->
85
+ preview_select_image $(e.currentTarget).attr('src')
86
+ return
87
+
88
+ $("#form-actions-cross").click (e) ->
89
+ $($.fn.parseContentPreview.defaultOptions.preview_title).text("")
90
+ $($.fn.parseContentPreview.defaultOptions.preview_description).text("")
91
+ $($.fn.parseContentPreview.defaultOptions.preview_image).empty()
92
+ $(".images").empty()
93
+ $($.fn.parseContentPreview.defaultOptions.form_hidden_inputs_name).empty()
94
+
95
+ $("#form-actions-cross").hide()
96
+ return
97
+
98
+ # Expose
99
+ window.ContentPreview = ContentPreview
100
+ window.preview_select_image = preview_select_image
@@ -0,0 +1,4 @@
1
+ module ContentPreview
2
+ end
3
+
4
+ require 'content-preview/parser'
@@ -0,0 +1,77 @@
1
+ require 'open-uri'
2
+ require 'nokogiri'
3
+
4
+ module ContentPreview
5
+ class Parser
6
+ attr_accessor :title, :description, :images
7
+
8
+ def initialize(images = [])
9
+ self.images = images
10
+ end
11
+
12
+ def process(url)
13
+ return unless url =~ /^http\:\/\//
14
+
15
+ begin
16
+ result = {}
17
+ document = Nokogiri::HTML(open(url))
18
+ process_open_graph(document)
19
+ process_meta_data(document, url)
20
+
21
+ result['title'] = self.title
22
+ result['description'] = self.description
23
+ result['images'] = self.images
24
+
25
+ return result
26
+ rescue Exception => e
27
+ nil
28
+ end
29
+ end
30
+
31
+ def process_open_graph(document)
32
+ unless document.xpath('//meta[starts-with(@property, "og:")]').empty?
33
+ for tag in document.xpath('//meta[starts-with(@property, "og:")]') do
34
+ case tag.first.last
35
+ when 'og:title'
36
+ self.title = tag['content']
37
+
38
+ when 'og:description'
39
+ self.description = tag['content']
40
+
41
+ when 'og:image'
42
+ self.images << tag['content']
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ def process_meta_data(document, url)
49
+ unless self.title
50
+ unless document.css('title').empty?
51
+ self.title = document.css('title').text
52
+ end
53
+ end
54
+
55
+ if self.images.empty?
56
+ list = []
57
+ document.traverse do |el|
58
+ [el[:src], el[:href]].grep(/\.(jpg)$/i).map{|l| URI.join(url, l).to_s}.first(10).each do |image|
59
+ list << image
60
+ end
61
+ end
62
+
63
+ self.images = list
64
+ end
65
+
66
+ unless self.description
67
+ unless document.xpath('//meta[starts-with(@name, "")]').empty?
68
+ for tag in document.xpath('//meta[starts-with(@name, "")]') do
69
+ if %w(description).include?(tag.first.last)
70
+ self.description = tag['content']
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,31 @@
1
+ require 'content-preview/router/handlers/default'
2
+
3
+ module ContentPreview
4
+ module Router
5
+ class Base
6
+ def initialize(path = File.expand_path('../router/routes.yml', __FILE__))
7
+ @routes = YAML.load_file path
8
+ end
9
+
10
+ def call(env)
11
+ path = env['PATH_INFO']
12
+
13
+ until @routes.has_key? path do
14
+ path = path.rpartition('/').first
15
+ path = '/' if path.empty?
16
+ end
17
+
18
+ # require File.dirname(__FILE__) + '/' + @routes[path]
19
+
20
+ class_name = @routes[path].capitalize
21
+ Handlers.const_get(class_name).call env
22
+ end
23
+
24
+ class << self
25
+ def call *args
26
+ new.call *args
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,22 @@
1
+ module ContentPreview
2
+ module Router
3
+ module Handlers
4
+ class Default
5
+ def self.call(env)
6
+ req = Rack::Request.new(env)
7
+ if req.get?
8
+ [404, {'Content-Type' => 'text/html'}, StringIO.new('No content param found.')] if !req.params['url']
9
+ result = ContentPreview::Parser.new.process(req.params["url"])
10
+ if result
11
+ [200, {'Content-Type' => 'text/json'}, StringIO.new(result.to_json)]
12
+ else
13
+ [404, {'Content-Type' => 'text/html'}, StringIO.new('The content you asked could not be found.')]
14
+ end
15
+ else
16
+ [403, {'Content-Type' => 'text/html'}, StringIO.new('Unauthorized.')]
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,25 @@
1
+ require 'content-preview/server/handlers/default'
2
+
3
+ module ContentPreview
4
+ module Router
5
+ class Base
6
+ def initialize(path = File.expand_path('../routes.yml', __FILE__))
7
+ @routes = YAML.load_file path
8
+ end
9
+
10
+ def call(env)
11
+ path = env['PATH_INFO']
12
+
13
+ until @routes.has_key? path do
14
+ path = path.rpartition('/').first
15
+ path = '/' if path.empty?
16
+ end
17
+
18
+ require File.dirname(__FILE__) + '/' + @routes[path]
19
+
20
+ class_name = @routes[path].capitalize
21
+ Handlers.const_get(class_name).call env
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,2 @@
1
+ ---
2
+ / : default
@@ -0,0 +1,3 @@
1
+ module ContentPreview
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :content-preview do
3
+ # # Task goes here
4
+ # end
data/roadmap.txt ADDED
@@ -0,0 +1,90 @@
1
+ ROADMAP :
2
+
3
+ ----------------------------------------------------------------------
4
+
5
+ V.0.1 :
6
+
7
+ Développement du parser et de différentes stratégies permettant un traitement plus approfondi et spécifique pour certaines URLS connues.
8
+
9
+ Description très basique :
10
+
11
+ 1. Le parser récupère une URL en entrée
12
+ 2. Le parser d'URL s'occupe de récupérer la page HTML correspondant à l'URL
13
+ 3. Les headers checkés en priorité sont :
14
+ a. Les balise meta OpenGraph (og:xxx)
15
+ b. <title>, <meta description>
16
+ c. Les images contenues dans la page
17
+ 4. Le parser renvoie soit une réponse vide si rien n'est trouvé et sinon un hash de type :
18
+ {
19
+ title: "Super video",
20
+ description: "Excellent one, gotta love it",
21
+ type: "video",
22
+ images: [
23
+ "http://example.com/image1.jpg",
24
+ "http://example.com/image2.jpg",
25
+ "http://example.com/image3.jpg"
26
+ ]
27
+ }
28
+
29
+ ----------------------------------------------------------------------
30
+
31
+ V.0.2 :
32
+
33
+ Il faut transformer le composant en service HTTP très simple, recevant des requêtes POST ayant pour unique paramètre le champ contenant le texte de l'utilisateur à parser.
34
+
35
+ 1. Le service reçoit une réponse POST contenant un champ "content" contenant le texte à parser
36
+ 2. Il appelle ContentPreview#parse avec le champ "content" comme argument afin de déléguer la tâche au parser
37
+ 3. Selon la réponse successful ou non du parser, un code HTTP différent est renvoyé ainsi que le résultat du parsing ou non :
38
+ a. Le parser renvoie une réponse vide (nil, s'évaluant à false), indiquant que rien n'a été trouvé, le service renvoie un code 404
39
+ b. Le parser renvoie un hash (s'évaluant à true), celui-ci est converti en JSON et renvoyé avec un code 200
40
+
41
+
42
+ ----------------------------------------------------------------------
43
+
44
+ V.0.3 :
45
+
46
+ Développer un client JS (dépendant de jQuery) permettant de parser un contenu texte et/ou HTML, d'interroger le serveur sur d'éventuels contenus media et d'appeler un callback défini par l'utisateur si un contenu media est renvoyé.
47
+ Il s'accompagnera d'un plugin jQuery permettant l'utilisation de $.fn.data() afin de persister l'état de la preview et ne la rafraîchir qu'en cas de besoin.
48
+
49
+ Quelques spécifications :
50
+
51
+ 1. La méthode #parse est appelée sur le client et prend en argument :
52
+ a. une chaîne de caractères pouvant contenir du HTML
53
+ b. une fonction callback recevant comme unique argument un objet JS de type :
54
+ {
55
+ title: "xx",
56
+ description: "xxxxx",
57
+ image: "http://example.com/pic.jpg"
58
+ }
59
+ 2. La méthode parse du client s'occupe de récupérer la première URL contenue dans le chaîne de caractère passée en argument
60
+ 3. S'il s'agit d'une nouvelle URL, il envoie une requête $.post contenant l'URL extraite au service
61
+ 4. Le retour de la requête est traitée :
62
+ a. Si le serveur retourne un code HTTP 200, le contenu de la réponse JSON est parsé et le callback appelé
63
+ b. Si le serveur retourne un code HTTP 404,
64
+
65
+
66
+ Example d'utilisation du plugin:
67
+
68
+ // On indique au parser l'URL du service
69
+ ContentPreview.service_url = 'http://example.com/content-preview-service'
70
+ var $textarea = $('textarea#user-content-input')
71
+
72
+ $textarea.on('keyup', function() {
73
+ $textarea.parseContentPreview($textarea.val(), function(resp) {
74
+ // Traitement de la réponse
75
+ });
76
+ });
77
+
78
+ ----------------------------------------------------------------------
79
+
80
+ V.1 :
81
+
82
+ Une fois le service et le client JS testés complètement
83
+
84
+ ----------------------------------------------------------------------
85
+
86
+ Idées supplémentaires :
87
+
88
+ - Mise en place d'un cache (probablement avec Redis) permettant de stocker le hash de réponse et de ne pas rechecker une URL si celle-ci a déjà été stockée. (Peut être avec un EXPIRE en fonction du cache ... à voir)
89
+ - Authentification au niveau du service
90
+
@@ -0,0 +1,65 @@
1
+ #encoding: UTF-8!
2
+ require 'nokogiri'
3
+ require 'open-uri'
4
+
5
+ require_relative '../../lib/content-preview'
6
+
7
+ describe ContentPreview::Parser, '::process' do
8
+
9
+ before(:each) do
10
+ @content_preview = ContentPreview::Parser.new
11
+ end
12
+
13
+ it 'should respond to %w(title description pictures) attributes' do
14
+ @content_preview.should respond_to :title
15
+ @content_preview.should respond_to :description
16
+ @content_preview.should respond_to :images
17
+ end
18
+
19
+ describe ContentPreview::Parser, 'pictures attribute' do
20
+ it 'should be a list' do
21
+ @content_preview.images.should be_kind_of Array
22
+ end
23
+ end
24
+
25
+ it 'should not return nil if the url is correct' do
26
+ preview = @content_preview.process "http://www.google.com"
27
+ preview.should_not be_nil
28
+ end
29
+
30
+ it "returns nil when url isn't well formatted" do
31
+ preview = %w(example.com example http:/www.example.com www.example.com).reduce(nil) do |result, url|
32
+ result = result || @content_preview.process(url) != nil ? true : nil
33
+ end
34
+ preview.should be_nil
35
+ end
36
+
37
+ it "returns nil when domain name doesn't exist" do
38
+ preview = @content_preview.process "http://www.tezzdazfazfadada.dza"
39
+ preview.should be_nil
40
+ end
41
+
42
+ it "returns nil if URL can't be found by the remote server" do
43
+ preview = @content_preview.process "http://www.google.com/oidajzodjaozjcaozcaozcnazocna"
44
+ preview.should be_nil
45
+ end
46
+
47
+ it 'should return valid information when processed with Google url' do
48
+ preview = @content_preview.process "http://www.google.com"
49
+ preview.should_not be_nil
50
+ preview.should include({"title"=>"Google", "description"=>nil, "images"=>[]})
51
+
52
+ @content_preview.title.should_not be_nil
53
+ end
54
+
55
+ it 'should return valid attributes when processed with a Youtube video url' do
56
+ preview = @content_preview.process "http://www.youtube.com/watch?v=OK7pfLlsUQM"
57
+ preview.should_not be_nil
58
+ preview.should include(
59
+ {"title"=>"The Artist - Official Trailer [HD]", "description"=>"Subscribe http://ow.ly/3UVvY | Facebook http://ow.ly/3UVxn | Twitter http://ow.ly/3UVyA Release Date: 23 November 2011 Genre: Romance | Comedy | Drama Cast: ...", "images"=>["http://i4.ytimg.com/vi/OK7pfLlsUQM/mqdefault.jpg"]}
60
+ )
61
+
62
+ @content_preview.title.should_not be_nil
63
+ @content_preview.images.should_not be_empty
64
+ end
65
+ end
@@ -0,0 +1,17 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+ RSpec.configure do |config|
8
+ config.treat_symbols_as_metadata_keys_with_true_values = true
9
+ config.run_all_when_everything_filtered = true
10
+ config.filter_run :focus
11
+
12
+ # Run specs in random order to surface order dependencies. If you find an
13
+ # order dependency and want to debug it, you can fix the order by providing
14
+ # the seed, which is printed after each run.
15
+ # --seed 1234
16
+ config.order = 'random'
17
+ end
metadata ADDED
@@ -0,0 +1,170 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: content-preview
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Glyph
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-24 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: thor
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: nokogiri
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: rake
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
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: rack-cors
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
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
+ - !ruby/object:Gem::Dependency
79
+ name: rack-test
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: json
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ description: A simple service for getting URL page informations
111
+ email:
112
+ - vala@glyph.fr
113
+ executables:
114
+ - cp-server
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - .gitignore
119
+ - .rspec
120
+ - Gemfile
121
+ - Gemfile.lock
122
+ - MIT-LICENSE
123
+ - README.md
124
+ - Rakefile
125
+ - bin/cp-server
126
+ - config.ru
127
+ - content-preview.gemspec
128
+ - js/src/content-preview.coffee
129
+ - lib/content-preview.rb
130
+ - lib/content-preview/parser.rb
131
+ - lib/content-preview/router.rb
132
+ - lib/content-preview/router/handlers/default.rb
133
+ - lib/content-preview/router/router.rb
134
+ - lib/content-preview/router/routes.yml
135
+ - lib/content-preview/version.rb
136
+ - lib/tasks/content-preview_tasks.rake
137
+ - roadmap.txt
138
+ - spec/parser/parser_spec.rb
139
+ - spec/spec_helper.rb
140
+ homepage: http://glyph.fr
141
+ licenses: []
142
+ post_install_message:
143
+ rdoc_options: []
144
+ require_paths:
145
+ - lib
146
+ required_ruby_version: !ruby/object:Gem::Requirement
147
+ none: false
148
+ requirements:
149
+ - - ! '>='
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ segments:
153
+ - 0
154
+ hash: 1542849611858236016
155
+ required_rubygems_version: !ruby/object:Gem::Requirement
156
+ none: false
157
+ requirements:
158
+ - - ! '>='
159
+ - !ruby/object:Gem::Version
160
+ version: '0'
161
+ segments:
162
+ - 0
163
+ hash: 1542849611858236016
164
+ requirements: []
165
+ rubyforge_project:
166
+ rubygems_version: 1.8.23
167
+ signing_key:
168
+ specification_version: 3
169
+ summary: A simple service for getting URL page informations
170
+ test_files: []