evernicious 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.DS_Store +0 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +22 -0
- data/LICENSE.txt +20 -0
- data/Rakefile +50 -0
- data/VERSION +1 -0
- data/bin/evernicious +18 -0
- data/evernicious.gemspec +97 -0
- data/lib/.DS_Store +0 -0
- data/lib/evernicious.rb +7 -0
- data/lib/evernicious/.DS_Store +0 -0
- data/lib/evernicious/bookmarks_parser.rb +37 -0
- data/lib/evernicious/enex_builder.rb +50 -0
- data/lib/evernicious/runner.rb +21 -0
- data/spec/evernicious/bookmarks_parser_spec.rb +95 -0
- data/spec/evernicious/enex_builder_spec.rb +60 -0
- data/spec/evernicious/runner_spec.rb +26 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +61 -0
- data/spec/support/helpers.rb +15 -0
- data/spec/support/matchers.rb +68 -0
- metadata +247 -0
data/.DS_Store
ADDED
Binary file
|
data/Gemfile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
gem "nokogiri", "~>1.4.3"
|
4
|
+
|
5
|
+
# Add dependencies to develop your gem here.
|
6
|
+
# Include everything needed to run rake, tests, features, etc.
|
7
|
+
group :development do
|
8
|
+
gem "rspec", "~> 1.3.1"
|
9
|
+
gem "bundler", "~> 1.0.0"
|
10
|
+
gem "jeweler", "~> 1.5.2"
|
11
|
+
gem "rcov", ">= 0"
|
12
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
git (1.2.5)
|
5
|
+
jeweler (1.5.2)
|
6
|
+
bundler (~> 1.0.0)
|
7
|
+
git (>= 1.2.5)
|
8
|
+
rake
|
9
|
+
nokogiri (1.4.3.1)
|
10
|
+
rake (0.8.7)
|
11
|
+
rcov (0.9.8)
|
12
|
+
rspec (1.3.1)
|
13
|
+
|
14
|
+
PLATFORMS
|
15
|
+
ruby
|
16
|
+
|
17
|
+
DEPENDENCIES
|
18
|
+
bundler (~> 1.0.0)
|
19
|
+
jeweler (~> 1.5.2)
|
20
|
+
nokogiri (~> 1.4.3)
|
21
|
+
rcov
|
22
|
+
rspec (~> 1.3.1)
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Jorge Manrubia
|
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/Rakefile
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'rake'
|
11
|
+
|
12
|
+
require 'jeweler'
|
13
|
+
Jeweler::Tasks.new do |gem|
|
14
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
15
|
+
gem.name = "evernicious"
|
16
|
+
gem.homepage = "http://github.com/jorgemanrubia/evernicious"
|
17
|
+
gem.license = "MIT"
|
18
|
+
gem.summary = %Q{A tool for converting delicious bookmarks (HTML file) to Evernote format (ENEX file)}
|
19
|
+
gem.description = %Q{A tool for converting delicious bookmarks (HTML file) to Evernote format (ENEX file). The delicious HTML file can be exported from del.icio.us. The generated ENEX file can be imported into Evernote using the official desktop Evernote client.}
|
20
|
+
gem.email = "jorge.manrubia@gmail.com"
|
21
|
+
gem.authors = ["Jorge Manrubia"]
|
22
|
+
|
23
|
+
# Include your dependencies below. Runtime dependencies are required when using your gem,
|
24
|
+
# and development dependencies are only needed for development (ie running rake tasks, tests, etc)
|
25
|
+
gem.add_runtime_dependency 'nokogiri', '> 1.4.3'
|
26
|
+
|
27
|
+
gem.add_development_dependency 'rspec', '> 1.3.1'
|
28
|
+
gem.add_development_dependency 'bundler', '> 1.0.0'
|
29
|
+
gem.add_development_dependency 'jeweler', '> 1.5.2'
|
30
|
+
gem.add_development_dependency 'rcov', '> 0'
|
31
|
+
|
32
|
+
gem.executables = ['evernicious']
|
33
|
+
end
|
34
|
+
Jeweler::RubygemsDotOrgTasks.new
|
35
|
+
|
36
|
+
require 'spec/rake/spectask'
|
37
|
+
|
38
|
+
Spec::Rake::SpecTask.new do |task|
|
39
|
+
task.spec_opts = ["--color"]
|
40
|
+
end
|
41
|
+
|
42
|
+
require 'rake/rdoctask'
|
43
|
+
Rake::RDocTask.new do |rdoc|
|
44
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
45
|
+
|
46
|
+
rdoc.rdoc_dir = 'rdoc'
|
47
|
+
rdoc.title = "evernicious #{version}"
|
48
|
+
rdoc.rdoc_files.include('README*')
|
49
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
50
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.9.0
|
data/bin/evernicious
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'evernicious'
|
4
|
+
|
5
|
+
if ARGV.size != 1
|
6
|
+
puts "Usage: evernicious [delicious bookmars file]"
|
7
|
+
exit 0
|
8
|
+
end
|
9
|
+
|
10
|
+
begin
|
11
|
+
puts "Converting '#{ARGV[0]}'..."
|
12
|
+
Evernicious::Runner.generate_evernote_file(ARGV[0])
|
13
|
+
puts "Evernote notes file generated: '#{ARGV[0]}.enex'"
|
14
|
+
rescue Exception => e
|
15
|
+
puts "Error: #{e.message}"
|
16
|
+
exit 1
|
17
|
+
end
|
18
|
+
|
data/evernicious.gemspec
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{evernicious}
|
8
|
+
s.version = "0.9.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Jorge Manrubia"]
|
12
|
+
s.date = %q{2011-01-02}
|
13
|
+
s.default_executable = %q{evernicious}
|
14
|
+
s.description = %q{A tool for converting delicious bookmarks (HTML file) to Evernote format (ENEX file). The delicious HTML file can be exported from del.icio.us. The generated ENEX file can be imported into Evernote using the official desktop Evernote client.}
|
15
|
+
s.email = %q{jorge.manrubia@gmail.com}
|
16
|
+
s.executables = ["evernicious"]
|
17
|
+
s.extra_rdoc_files = [
|
18
|
+
"LICENSE.txt"
|
19
|
+
]
|
20
|
+
s.files = [
|
21
|
+
".DS_Store",
|
22
|
+
"Gemfile",
|
23
|
+
"Gemfile.lock",
|
24
|
+
"LICENSE.txt",
|
25
|
+
"Rakefile",
|
26
|
+
"VERSION",
|
27
|
+
"bin/evernicious",
|
28
|
+
"evernicious.gemspec",
|
29
|
+
"lib/.DS_Store",
|
30
|
+
"lib/evernicious.rb",
|
31
|
+
"lib/evernicious/.DS_Store",
|
32
|
+
"lib/evernicious/bookmarks_parser.rb",
|
33
|
+
"lib/evernicious/enex_builder.rb",
|
34
|
+
"lib/evernicious/runner.rb",
|
35
|
+
"spec/evernicious/bookmarks_parser_spec.rb",
|
36
|
+
"spec/evernicious/enex_builder_spec.rb",
|
37
|
+
"spec/evernicious/runner_spec.rb",
|
38
|
+
"spec/spec.opts",
|
39
|
+
"spec/spec_helper.rb",
|
40
|
+
"spec/support/helpers.rb",
|
41
|
+
"spec/support/matchers.rb"
|
42
|
+
]
|
43
|
+
s.homepage = %q{http://github.com/jorgemanrubia/evernicious}
|
44
|
+
s.licenses = ["MIT"]
|
45
|
+
s.require_paths = ["lib"]
|
46
|
+
s.rubygems_version = %q{1.3.7}
|
47
|
+
s.summary = %q{A tool for converting delicious bookmarks (HTML file) to Evernote format (ENEX file)}
|
48
|
+
s.test_files = [
|
49
|
+
"spec/evernicious/bookmarks_parser_spec.rb",
|
50
|
+
"spec/evernicious/enex_builder_spec.rb",
|
51
|
+
"spec/evernicious/runner_spec.rb",
|
52
|
+
"spec/spec_helper.rb",
|
53
|
+
"spec/support/helpers.rb",
|
54
|
+
"spec/support/matchers.rb"
|
55
|
+
]
|
56
|
+
|
57
|
+
if s.respond_to? :specification_version then
|
58
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
59
|
+
s.specification_version = 3
|
60
|
+
|
61
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
62
|
+
s.add_runtime_dependency(%q<nokogiri>, ["~> 1.4.3"])
|
63
|
+
s.add_development_dependency(%q<rspec>, ["~> 1.3.1"])
|
64
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
65
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
|
66
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
67
|
+
s.add_runtime_dependency(%q<nokogiri>, ["> 1.4.3"])
|
68
|
+
s.add_development_dependency(%q<rspec>, ["> 1.3.1"])
|
69
|
+
s.add_development_dependency(%q<bundler>, ["> 1.0.0"])
|
70
|
+
s.add_development_dependency(%q<jeweler>, ["> 1.5.2"])
|
71
|
+
s.add_development_dependency(%q<rcov>, ["> 0"])
|
72
|
+
else
|
73
|
+
s.add_dependency(%q<nokogiri>, ["~> 1.4.3"])
|
74
|
+
s.add_dependency(%q<rspec>, ["~> 1.3.1"])
|
75
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
76
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
77
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
78
|
+
s.add_dependency(%q<nokogiri>, ["> 1.4.3"])
|
79
|
+
s.add_dependency(%q<rspec>, ["> 1.3.1"])
|
80
|
+
s.add_dependency(%q<bundler>, ["> 1.0.0"])
|
81
|
+
s.add_dependency(%q<jeweler>, ["> 1.5.2"])
|
82
|
+
s.add_dependency(%q<rcov>, ["> 0"])
|
83
|
+
end
|
84
|
+
else
|
85
|
+
s.add_dependency(%q<nokogiri>, ["~> 1.4.3"])
|
86
|
+
s.add_dependency(%q<rspec>, ["~> 1.3.1"])
|
87
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
88
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
89
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
90
|
+
s.add_dependency(%q<nokogiri>, ["> 1.4.3"])
|
91
|
+
s.add_dependency(%q<rspec>, ["> 1.3.1"])
|
92
|
+
s.add_dependency(%q<bundler>, ["> 1.0.0"])
|
93
|
+
s.add_dependency(%q<jeweler>, ["> 1.5.2"])
|
94
|
+
s.add_dependency(%q<rcov>, ["> 0"])
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
data/lib/.DS_Store
ADDED
Binary file
|
data/lib/evernicious.rb
ADDED
Binary file
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Evernicious
|
2
|
+
class BookmarksParser
|
3
|
+
def parse(bookmarks_code_source)
|
4
|
+
document = Nokogiri::HTML(bookmarks_code_source, nil, 'UTF-8')
|
5
|
+
#Delicious HTML format has unclosed tags and presents problems with nokogiri. See XPath expression at http://goo.gl/Cm7Zn
|
6
|
+
build_bookmars document.xpath('//dt/a | //dt[a]/following-sibling::*[1][self::dd]')
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def build_bookmars(a_or_dd_nodes)
|
12
|
+
bookmarks = []
|
13
|
+
a_or_dd_nodes.each_with_index do |a_or_dd_node, index|
|
14
|
+
next if is_dd_node?(a_or_dd_node)
|
15
|
+
bookmarks << build_bookmark(a_or_dd_node, a_or_dd_nodes[index+1])
|
16
|
+
end
|
17
|
+
bookmarks
|
18
|
+
end
|
19
|
+
|
20
|
+
def build_bookmark(a_node, next_node)
|
21
|
+
OpenStruct.new :title=>a_node.text,
|
22
|
+
:added_at=>Time.at(a_node['add_date'].to_i),
|
23
|
+
:url=>a_node['href'],
|
24
|
+
:tags=>build_tags_from_string(a_node['tags']),
|
25
|
+
:comments=>is_dd_node?(next_node) ? next_node.inner_html : ''
|
26
|
+
end
|
27
|
+
|
28
|
+
def is_dd_node?(node)
|
29
|
+
node && node.name == 'dd'
|
30
|
+
end
|
31
|
+
|
32
|
+
def build_tags_from_string(tags_as_string)
|
33
|
+
tags_as_string ? tags_as_string.split(/,/).find_all{|tag| !tag.strip.empty?} : []
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Evernicious
|
2
|
+
class EnexBuilder
|
3
|
+
def build_enex_document(bookmarks)
|
4
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
5
|
+
xml.send('en-export'.to_sym){
|
6
|
+
bookmarks.each do |bookmark|
|
7
|
+
build_bookmark(xml, bookmark)
|
8
|
+
end
|
9
|
+
}
|
10
|
+
end
|
11
|
+
Nokogiri::XML(builder.to_xml)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def build_bookmark(xml, bookmark)
|
17
|
+
xml.note{
|
18
|
+
xml.title bookmark.title
|
19
|
+
xml.content{
|
20
|
+
xml.cdata(within_enex_note(bookmark.comments))
|
21
|
+
}
|
22
|
+
xml.created as_evernote_date(bookmark.added_at)
|
23
|
+
xml.updated as_evernote_date(bookmark.added_at)
|
24
|
+
xml.send('source-url'.to_sym, bookmark.url)
|
25
|
+
bookmark.tags.each do |tag|
|
26
|
+
xml.tag tag
|
27
|
+
end
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
def within_enex_note(content)
|
32
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
33
|
+
xml.doc.create_internal_subset('en-note', nil, "http://xml.evernote.com/pub/enml2.dtd")
|
34
|
+
xml.send('en-note'.to_sym){
|
35
|
+
xml.text(content)
|
36
|
+
}
|
37
|
+
end
|
38
|
+
builder.to_xml
|
39
|
+
end
|
40
|
+
|
41
|
+
def as_evernote_date(delicious_date)
|
42
|
+
delicious_date.strftime("%Y%m%dT%H%M%SZ")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# bookmarks = BookmarksParser.new.parse(File.open("d.htm", "r"))
|
47
|
+
# puts EnexBuilder.new.build_enex_document(bookmarks).to_xml(:encoding => 'UTF-8')
|
48
|
+
end
|
49
|
+
|
50
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Evernicious
|
2
|
+
class Runner
|
3
|
+
def self.generate_evernote_file(delicious_bookmarks_file_path)
|
4
|
+
bookmarks = parse_delicious_bookmarks(delicious_bookmarks_file_path)
|
5
|
+
evernote_contents = EnexBuilder.new.build_enex_document(bookmarks).to_xml(:encoding => 'UTF-8')
|
6
|
+
write_contents_to_output_file("#{delicious_bookmarks_file_path}.enex", evernote_contents)
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def self.parse_delicious_bookmarks(delicious_bookmarks_file_path)
|
12
|
+
delicious_bookmarks_file = File.open(delicious_bookmarks_file_path, "r")
|
13
|
+
BookmarksParser.new.parse(delicious_bookmarks_file)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.write_contents_to_output_file(output_file_path, contents)
|
17
|
+
File.open(output_file_path, "w"){|file| file.write(contents)}
|
18
|
+
output_file_path
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Evernicious::BookmarksParser do
|
4
|
+
it "should return an empty list when no bookmarks found" do
|
5
|
+
''.should be_parsed_as []
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should parse a simple bookmark" do
|
9
|
+
%{
|
10
|
+
<DL><p><DT><A HREF="http://the.url" ADD_DATE="1280913776" PRIVATE="0" TAGS="">The title</A></DL>
|
11
|
+
}.should be_parsed_as [
|
12
|
+
OpenStruct.new(:title=>'The title', :url=>'http://the.url', :added_at=>Time.at(1280913776), :comments=>"", :tags=>[])
|
13
|
+
]
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should parse a bookmark with a comment" do
|
17
|
+
%{
|
18
|
+
<DL><p><DT><A HREF="http://the.url" ADD_DATE="1380913776" PRIVATE="0" TAGS="">The title</A>
|
19
|
+
<DD>This is the comment</DL>
|
20
|
+
}.should be_parsed_as [
|
21
|
+
OpenStruct.new(:title=>'The title', :url=>'http://the.url', :added_at=>Time.at(1380913776), :comments=>"This is the comment", :tags=>[])
|
22
|
+
]
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should parse a bookmark with an HTML comment with breaklines" do
|
26
|
+
html_comment = %{First line<br>Second line<br>}
|
27
|
+
|
28
|
+
%{
|
29
|
+
<DL><p><DT><A HREF="http://the.url" ADD_DATE="1380913776" PRIVATE="0" TAGS="">The title</A>
|
30
|
+
<DD>#{html_comment}</DL>
|
31
|
+
}.should be_parsed_as [
|
32
|
+
OpenStruct.new(:title=>'The title', :url=>'http://the.url', :added_at=>Time.at(1380913776), :comments=>html_comment, :tags=>[])
|
33
|
+
]
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should parse a bookmark with one tags" do
|
37
|
+
%{
|
38
|
+
<DL><p><DT><A HREF="http://the.url" ADD_DATE="1380913776" PRIVATE="0" TAGS="tag-1">The title</A>
|
39
|
+
<DD>This is the comment</DL>
|
40
|
+
}.should be_parsed_as [
|
41
|
+
OpenStruct.new(:title=>'The title', :url=>'http://the.url', :added_at=>Time.at(1380913776), :comments=>"This is the comment", :tags=>%W(tag-1))
|
42
|
+
]
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should parse a bookmark with no TAGS attribute" do
|
46
|
+
%{
|
47
|
+
<DL><p><DT><A HREF="http://the.url" ADD_DATE="1380913776" PRIVATE="0">The title</A>
|
48
|
+
<DD>This is the comment</DL>
|
49
|
+
}.should be_parsed_as [
|
50
|
+
OpenStruct.new(:title=>'The title', :url=>'http://the.url', :added_at=>Time.at(1380913776), :comments=>"This is the comment", :tags=>[])
|
51
|
+
]
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should parse a bookmark with many tags" do
|
55
|
+
%{
|
56
|
+
<DL><p><DT><A HREF="http://the.url" ADD_DATE="1380913776" PRIVATE="0" TAGS="tag-1,tag-2,tag-3">The title</A>
|
57
|
+
<DD>This is the comment</DL>
|
58
|
+
}.should be_parsed_as [
|
59
|
+
OpenStruct.new(:title=>'The title', :url=>'http://the.url', :added_at=>Time.at(1380913776), :comments=>"This is the comment", :tags=>%W(tag-1 tag-2 tag-3))
|
60
|
+
]
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should parse a bookmark with tags ignoring empty ones" do
|
64
|
+
%{
|
65
|
+
<DL><p><DT><A HREF="http://the.url" ADD_DATE="1380913776" PRIVATE="0" TAGS="tag-1, ,,tag-2, ,,tag-3">The title</A>
|
66
|
+
<DD>This is the comment</DL>
|
67
|
+
}.should be_parsed_as [
|
68
|
+
OpenStruct.new(:title=>'The title', :url=>'http://the.url', :added_at=>Time.at(1380913776), :comments=>"This is the comment", :tags=>%W(tag-1 tag-2 tag-3))
|
69
|
+
]
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
it "should parse many bookmarks" do
|
74
|
+
%{
|
75
|
+
<DL><DT><A HREF="http://the.url.1" ADD_DATE="1380913770" PRIVATE="0" TAGS="">The title 1</A><DD>This is the comment 1<DT><A HREF="http://the.url.2" ADD_DATE="1380913771" PRIVATE="0" TAGS="tag-1,tag-2,tag-3">The title 2</A>
|
76
|
+
}.should be_parsed_as [
|
77
|
+
OpenStruct.new(:title=>'The title 1', :url=>'http://the.url.1', :added_at=>Time.at(1380913770), :comments=>"This is the comment 1", :tags=>[]),
|
78
|
+
OpenStruct.new(:title=>'The title 2', :url=>'http://the.url.2', :added_at=>Time.at(1380913771), :comments=>"", :tags=>%W(tag-1 tag-2 tag-3))
|
79
|
+
]
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should parse bookmars without comments (without dd nodes)" do
|
83
|
+
%{
|
84
|
+
<DL><DT><A HREF="http://the.url.1" ADD_DATE="1380913770" PRIVATE="0" TAGS="">The title 1</A>
|
85
|
+
<DT><A HREF="http://the.url.2" ADD_DATE="1380913771" PRIVATE="0" TAGS="">The title 2</A>
|
86
|
+
<DD>Some comment</DL>
|
87
|
+
}.should be_parsed_as [
|
88
|
+
OpenStruct.new(:title=>'The title 1', :url=>'http://the.url.1', :added_at=>Time.at(1380913770), :comments=>"", :tags=>[]),
|
89
|
+
OpenStruct.new(:title=>'The title 2', :url=>'http://the.url.2', :added_at=>Time.at(1380913771), :comments=>"Some comment", :tags=>[])
|
90
|
+
]
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
|
95
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Evernicious::EnexBuilder do
|
4
|
+
it "should generate a proper Enex document for a simple bookmark without comments nor tags" do
|
5
|
+
[{:title=>'The title', :url=>'http://the.url', :added_at=>Time.at(1380913776), :comments=>"", :tags=>[]}].should generate_enex_document [{
|
6
|
+
:title=>"The title",
|
7
|
+
:content=>"",
|
8
|
+
:url=>'http://the.url',
|
9
|
+
:created=>Time.at(1380913776),
|
10
|
+
:updated=>Time.at(1380913776)
|
11
|
+
}]
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should generate a proper Enex document for a simple bookmark with comments" do
|
15
|
+
[{:title=>'The title', :url=>'http://the.url', :added_at=>Time.at(1380913776), :comments=>"The comment 1", :tags=>[]}].should generate_enex_document [{
|
16
|
+
:title=>"The title",
|
17
|
+
:content=>"The comment 1",
|
18
|
+
:url=>'http://the.url',
|
19
|
+
:created=>Time.at(1380913776),
|
20
|
+
:updated=>Time.at(1380913776)
|
21
|
+
}]
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should generate a proper Enex document for a simple bookmark with tags" do
|
25
|
+
[{:title=>'The title', :url=>'http://the.url', :added_at=>Time.at(1380913776), :comments=>"", :tags=>%W{tag-1 tag-2 tag-3}}].should generate_enex_document [{
|
26
|
+
:title=>"The title",
|
27
|
+
:content=>"",
|
28
|
+
:url=>'http://the.url',
|
29
|
+
:created=>Time.at(1380913776),
|
30
|
+
:updated=>Time.at(1380913776),
|
31
|
+
:tags=>%W{tag-1 tag-2 tag-3}
|
32
|
+
}]
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should generate a proper Enex document for two bookmarks" do
|
36
|
+
[{:title=>'The title 1', :url=>'http://the.url.1', :added_at=>Time.at(1380913770), :comments=>"comment 1", :tags=>%W{tag-1-1 tag-1-2 tag-1-3}},
|
37
|
+
{:title=>'The title 2', :url=>'http://the.url.2', :added_at=>Time.at(1380913771), :comments=>"comment 2", :tags=>%W{tag-2-1 tag-2-2 tag-2-3}}
|
38
|
+
].should generate_enex_document [
|
39
|
+
{
|
40
|
+
:title=>"The title 1",
|
41
|
+
:content=>"comment 1",
|
42
|
+
:url=>'http://the.url.1',
|
43
|
+
:created=>Time.at(1380913770),
|
44
|
+
:updated=>Time.at(1380913770),
|
45
|
+
:tags=>%W{tag-1-1 tag-1-2 tag-1-3}
|
46
|
+
},
|
47
|
+
{
|
48
|
+
:title=>"The title 2",
|
49
|
+
:content=>"comment 2",
|
50
|
+
:url=>'http://the.url.2',
|
51
|
+
:created=>Time.at(1380913771),
|
52
|
+
:updated=>Time.at(1380913771),
|
53
|
+
:tags=>%W{tag-2-1 tag-2-2 tag-2-3}
|
54
|
+
}]
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Evernicious::Runner do
|
4
|
+
describe "generate_evernote_file" do
|
5
|
+
before(:each) do
|
6
|
+
@input_file = mock('the input file', "empty?"=>nil)
|
7
|
+
@bookmarks_parser = mock('the bookmarks parser')
|
8
|
+
@bookmarks = mock('the bookmarks')
|
9
|
+
@enex_builder = mock('the enex builder')
|
10
|
+
@output_file = mock('the output file')
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should parse the provided bookmars file, build the enex document for them and write the results in a file which name is the source name plus the 'enex' extension" do
|
14
|
+
File.should_receive(:open).with('the-input-file.htm', 'r').and_return @input_file
|
15
|
+
Evernicious::BookmarksParser.should_receive(:new).and_return @bookmarks_parser
|
16
|
+
@bookmarks_parser.should_receive(:parse).with(@input_file).and_return @bookmarks
|
17
|
+
|
18
|
+
Evernicious::EnexBuilder.should_receive(:new).and_return @enex_builder
|
19
|
+
@enex_builder.should_receive(:build_enex_document).with(@bookmarks).and_return mock('the evernote xml document', :to_xml=>'the evernote xml')
|
20
|
+
|
21
|
+
File.should_receive(:open).with('the-input-file.htm.enex', 'w').and_yield @output_file
|
22
|
+
@output_file.should_receive(:write).with('the evernote xml')
|
23
|
+
Evernicious::Runner.generate_evernote_file('the-input-file.htm')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
|
2
|
+
# $:.unshift File.expand_path('..', __FILE__)
|
3
|
+
# $:.unshift File.expand_path('../../lib', __FILE__)
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'spec'
|
7
|
+
require 'spec/autorun'
|
8
|
+
require 'spec/matchers'
|
9
|
+
require 'evernicious'
|
10
|
+
|
11
|
+
# Uncomment the next line to use webrat's matchers
|
12
|
+
#require 'webrat/integrations/rspec-rails'
|
13
|
+
|
14
|
+
module Evernicious
|
15
|
+
module Spec
|
16
|
+
class Initializer
|
17
|
+
attr_accessor :config
|
18
|
+
|
19
|
+
REQUIRED_PATHS = [
|
20
|
+
"/support/**/*.rb",
|
21
|
+
"../lib/**/*.rb"
|
22
|
+
]
|
23
|
+
|
24
|
+
def initialize(config)
|
25
|
+
@config = config
|
26
|
+
end
|
27
|
+
|
28
|
+
def configure
|
29
|
+
require_supporting_files
|
30
|
+
init_rspec_config
|
31
|
+
end
|
32
|
+
|
33
|
+
def require_supporting_files
|
34
|
+
REQUIRED_PATHS.each do |file_pattern|
|
35
|
+
Dir[File.dirname(__FILE__) + file_pattern].each do |file|
|
36
|
+
require file
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def init_rspec_config
|
42
|
+
config.include BookmarkHelpers
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
Spec::Runner.configure do |config|
|
50
|
+
Evernicious::Spec::Initializer.new(config).configure()
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
class Spec::Matchers::Matcher
|
55
|
+
include BookmarkHelpers
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module BookmarkHelpers
|
2
|
+
def within_bookmarks_document(content)
|
3
|
+
%{
|
4
|
+
<!DOCTYPE NETSCAPE-Bookmark-file-1>
|
5
|
+
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
|
6
|
+
<TITLE>Bookmarks</TITLE>
|
7
|
+
<H1>Bookmarks</H1>
|
8
|
+
#{content}
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
def build_list_of_objects(properties_list)
|
13
|
+
properties_list.collect{|properties| OpenStruct.new(properties)}
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
|
2
|
+
Spec::Matchers.define :be_parsed_as do |expected_bookmarks|
|
3
|
+
match do |bookmarks_code|
|
4
|
+
@parsed_bookmarks = Evernicious::BookmarksParser.new().parse(within_bookmarks_document(bookmarks_code))
|
5
|
+
@parsed_bookmarks.should == expected_bookmarks
|
6
|
+
end
|
7
|
+
|
8
|
+
failure_message_for_should do |actual_bookmarks|
|
9
|
+
"expecting to parse:
|
10
|
+
#{expected_bookmarks}
|
11
|
+
|
12
|
+
but parsed:
|
13
|
+
#{@parsed_bookmarks}"
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
Spec::Matchers.define :generate_enex_document do |expected_nodes_properties_list|
|
19
|
+
|
20
|
+
def compare_contents(expected_content, actual_content_cdata)
|
21
|
+
actual_content = Nokogiri::XML(actual_content_cdata).at_css('en-note').text
|
22
|
+
actual_content == expected_content
|
23
|
+
end
|
24
|
+
|
25
|
+
def compare_dates(expected_date_with_delicious_format, actual_date)
|
26
|
+
expected_date = expected_date_with_delicious_format.strftime("%Y%m%dT%H%M%SZ")
|
27
|
+
expected_date == expected_date
|
28
|
+
end
|
29
|
+
|
30
|
+
def compare_tags(expected_tags, tag_nodes)
|
31
|
+
return tag_nodes.empty? if !expected_tags || expected_tags.empty?
|
32
|
+
tag_nodes.collect{|tag_node| tag_node.text} == expected_tags
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
match do |bookmarks_properties_list|
|
37
|
+
bookmarks = build_list_of_objects(bookmarks_properties_list)
|
38
|
+
expected_nodes = build_list_of_objects(expected_nodes_properties_list)
|
39
|
+
|
40
|
+
@generated_enex_document = Evernicious::EnexBuilder.new().build_enex_document(bookmarks)
|
41
|
+
|
42
|
+
generated_notes = @generated_enex_document.css('note')
|
43
|
+
matched = bookmarks.size == generated_notes.size
|
44
|
+
generated_notes.each_with_index do |enex_note_node, index|
|
45
|
+
expected_node = expected_nodes[index]
|
46
|
+
|
47
|
+
unless !matched
|
48
|
+
matched = enex_note_node.at_css('title').text == expected_node.title &&
|
49
|
+
matched = enex_note_node.at_css('source-url').text == expected_node.url &&
|
50
|
+
compare_contents(expected_node.content, enex_note_node.at_css('content').child.text) &&
|
51
|
+
compare_dates(expected_node.created, enex_note_node.at_css('created').text) &&
|
52
|
+
compare_dates(expected_node.created, enex_note_node.at_css('updated').text) &&
|
53
|
+
compare_tags(expected_node.tags, enex_note_node.css('tag'))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
matched
|
58
|
+
end
|
59
|
+
|
60
|
+
failure_message_for_should do |actual_bookmarks|
|
61
|
+
"expecting to generate a document with the following nodes:
|
62
|
+
#{expected_nodes_properties_list.inspect}
|
63
|
+
|
64
|
+
but generated the next document:
|
65
|
+
#{@generated_enex_document}"
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
metadata
ADDED
@@ -0,0 +1,247 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: evernicious
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 59
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 9
|
9
|
+
- 0
|
10
|
+
version: 0.9.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Jorge Manrubia
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-01-02 00:00:00 +01:00
|
19
|
+
default_executable: evernicious
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - ~>
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
hash: 1
|
28
|
+
segments:
|
29
|
+
- 1
|
30
|
+
- 4
|
31
|
+
- 3
|
32
|
+
version: 1.4.3
|
33
|
+
type: :runtime
|
34
|
+
name: nokogiri
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 25
|
44
|
+
segments:
|
45
|
+
- 1
|
46
|
+
- 3
|
47
|
+
- 1
|
48
|
+
version: 1.3.1
|
49
|
+
type: :development
|
50
|
+
name: rspec
|
51
|
+
prerelease: false
|
52
|
+
version_requirements: *id002
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ~>
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 23
|
60
|
+
segments:
|
61
|
+
- 1
|
62
|
+
- 0
|
63
|
+
- 0
|
64
|
+
version: 1.0.0
|
65
|
+
type: :development
|
66
|
+
name: bundler
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *id003
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
71
|
+
none: false
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
hash: 7
|
76
|
+
segments:
|
77
|
+
- 1
|
78
|
+
- 5
|
79
|
+
- 2
|
80
|
+
version: 1.5.2
|
81
|
+
type: :development
|
82
|
+
name: jeweler
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: *id004
|
85
|
+
- !ruby/object:Gem::Dependency
|
86
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
hash: 3
|
92
|
+
segments:
|
93
|
+
- 0
|
94
|
+
version: "0"
|
95
|
+
type: :development
|
96
|
+
name: rcov
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: *id005
|
99
|
+
- !ruby/object:Gem::Dependency
|
100
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
101
|
+
none: false
|
102
|
+
requirements:
|
103
|
+
- - ">"
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
hash: 1
|
106
|
+
segments:
|
107
|
+
- 1
|
108
|
+
- 4
|
109
|
+
- 3
|
110
|
+
version: 1.4.3
|
111
|
+
type: :runtime
|
112
|
+
name: nokogiri
|
113
|
+
prerelease: false
|
114
|
+
version_requirements: *id006
|
115
|
+
- !ruby/object:Gem::Dependency
|
116
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
117
|
+
none: false
|
118
|
+
requirements:
|
119
|
+
- - ">"
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
hash: 25
|
122
|
+
segments:
|
123
|
+
- 1
|
124
|
+
- 3
|
125
|
+
- 1
|
126
|
+
version: 1.3.1
|
127
|
+
type: :development
|
128
|
+
name: rspec
|
129
|
+
prerelease: false
|
130
|
+
version_requirements: *id007
|
131
|
+
- !ruby/object:Gem::Dependency
|
132
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
133
|
+
none: false
|
134
|
+
requirements:
|
135
|
+
- - ">"
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
hash: 23
|
138
|
+
segments:
|
139
|
+
- 1
|
140
|
+
- 0
|
141
|
+
- 0
|
142
|
+
version: 1.0.0
|
143
|
+
type: :development
|
144
|
+
name: bundler
|
145
|
+
prerelease: false
|
146
|
+
version_requirements: *id008
|
147
|
+
- !ruby/object:Gem::Dependency
|
148
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
149
|
+
none: false
|
150
|
+
requirements:
|
151
|
+
- - ">"
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
hash: 7
|
154
|
+
segments:
|
155
|
+
- 1
|
156
|
+
- 5
|
157
|
+
- 2
|
158
|
+
version: 1.5.2
|
159
|
+
type: :development
|
160
|
+
name: jeweler
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: *id009
|
163
|
+
- !ruby/object:Gem::Dependency
|
164
|
+
requirement: &id010 !ruby/object:Gem::Requirement
|
165
|
+
none: false
|
166
|
+
requirements:
|
167
|
+
- - ">"
|
168
|
+
- !ruby/object:Gem::Version
|
169
|
+
hash: 3
|
170
|
+
segments:
|
171
|
+
- 0
|
172
|
+
version: "0"
|
173
|
+
type: :development
|
174
|
+
name: rcov
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: *id010
|
177
|
+
description: A tool for converting delicious bookmarks (HTML file) to Evernote format (ENEX file). The delicious HTML file can be exported from del.icio.us. The generated ENEX file can be imported into Evernote using the official desktop Evernote client.
|
178
|
+
email: jorge.manrubia@gmail.com
|
179
|
+
executables:
|
180
|
+
- evernicious
|
181
|
+
extensions: []
|
182
|
+
|
183
|
+
extra_rdoc_files:
|
184
|
+
- LICENSE.txt
|
185
|
+
files:
|
186
|
+
- .DS_Store
|
187
|
+
- Gemfile
|
188
|
+
- Gemfile.lock
|
189
|
+
- LICENSE.txt
|
190
|
+
- Rakefile
|
191
|
+
- VERSION
|
192
|
+
- bin/evernicious
|
193
|
+
- evernicious.gemspec
|
194
|
+
- lib/.DS_Store
|
195
|
+
- lib/evernicious.rb
|
196
|
+
- lib/evernicious/.DS_Store
|
197
|
+
- lib/evernicious/bookmarks_parser.rb
|
198
|
+
- lib/evernicious/enex_builder.rb
|
199
|
+
- lib/evernicious/runner.rb
|
200
|
+
- spec/evernicious/bookmarks_parser_spec.rb
|
201
|
+
- spec/evernicious/enex_builder_spec.rb
|
202
|
+
- spec/evernicious/runner_spec.rb
|
203
|
+
- spec/spec.opts
|
204
|
+
- spec/spec_helper.rb
|
205
|
+
- spec/support/helpers.rb
|
206
|
+
- spec/support/matchers.rb
|
207
|
+
has_rdoc: true
|
208
|
+
homepage: http://github.com/jorgemanrubia/evernicious
|
209
|
+
licenses:
|
210
|
+
- MIT
|
211
|
+
post_install_message:
|
212
|
+
rdoc_options: []
|
213
|
+
|
214
|
+
require_paths:
|
215
|
+
- lib
|
216
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
217
|
+
none: false
|
218
|
+
requirements:
|
219
|
+
- - ">="
|
220
|
+
- !ruby/object:Gem::Version
|
221
|
+
hash: 3
|
222
|
+
segments:
|
223
|
+
- 0
|
224
|
+
version: "0"
|
225
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
226
|
+
none: false
|
227
|
+
requirements:
|
228
|
+
- - ">="
|
229
|
+
- !ruby/object:Gem::Version
|
230
|
+
hash: 3
|
231
|
+
segments:
|
232
|
+
- 0
|
233
|
+
version: "0"
|
234
|
+
requirements: []
|
235
|
+
|
236
|
+
rubyforge_project:
|
237
|
+
rubygems_version: 1.3.7
|
238
|
+
signing_key:
|
239
|
+
specification_version: 3
|
240
|
+
summary: A tool for converting delicious bookmarks (HTML file) to Evernote format (ENEX file)
|
241
|
+
test_files:
|
242
|
+
- spec/evernicious/bookmarks_parser_spec.rb
|
243
|
+
- spec/evernicious/enex_builder_spec.rb
|
244
|
+
- spec/evernicious/runner_spec.rb
|
245
|
+
- spec/spec_helper.rb
|
246
|
+
- spec/support/helpers.rb
|
247
|
+
- spec/support/matchers.rb
|