content-preview 0.0.1

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.
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: []