xbel 0.2.3 → 0.2.4
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/VERSION +1 -1
- data/lib/nokogiri/decorators/xbel.rb +10 -1
- data/lib/nokogiri/decorators/xbel/folder.rb +24 -21
- data/lib/xbel.rb +23 -3
- data/test/test_xbel.rb +138 -108
- data/test/wikipedia.xbel +8 -8
- data/xbel.gemspec +1 -1
- metadata +1 -1
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.4
|
@@ -35,6 +35,10 @@ module Nokogiri::Decorators::XBEL
|
|
35
35
|
end
|
36
36
|
attr_reader :info
|
37
37
|
|
38
|
+
def attributes=(attributes)
|
39
|
+
attributes.each { |key, value| send "#{ key }=", value }
|
40
|
+
end
|
41
|
+
|
38
42
|
# Returns description of node.
|
39
43
|
def desc
|
40
44
|
if node = at('./desc') then node.content end
|
@@ -77,7 +81,12 @@ module Nokogiri::Decorators::XBEL
|
|
77
81
|
end
|
78
82
|
# Sets addition date.
|
79
83
|
def added=(value)
|
80
|
-
set_attribute 'added', value
|
84
|
+
set_attribute 'added', case value
|
85
|
+
when Time; value.strftime '%Y-%m-%d'
|
86
|
+
when String; value
|
87
|
+
else
|
88
|
+
raise ArgumentError
|
89
|
+
end
|
81
90
|
end
|
82
91
|
|
83
92
|
# Returns nil.
|
@@ -34,31 +34,31 @@ module Nokogiri::Decorators::XBEL
|
|
34
34
|
super
|
35
35
|
end
|
36
36
|
|
37
|
-
def build(type, attributes = {}
|
38
|
-
|
39
|
-
|
37
|
+
def build(type, attributes = {})
|
38
|
+
node = Nokogiri::XML::Node.new(type.to_s, document)
|
39
|
+
node.attributes = attributes
|
40
40
|
|
41
|
-
|
41
|
+
yield node if block_given?
|
42
|
+
|
43
|
+
node
|
42
44
|
end
|
43
45
|
|
44
46
|
# Builds a bookmark with given attributes and add it.
|
45
|
-
def
|
46
|
-
|
47
|
-
|
48
|
-
&block
|
47
|
+
def add_bookmark(title, href, attributes = {}, &block)
|
48
|
+
attributes = attributes.merge :title => title, :href => href
|
49
|
+
add_child build(:bookmark, attributes, &block)
|
49
50
|
end
|
50
51
|
# Builds a folder with given attributes and add it.
|
51
|
-
def
|
52
|
-
|
53
|
-
|
54
|
-
&block
|
52
|
+
def add_folder(title, attributes = {}, &block)
|
53
|
+
attributes = attributes.merge :title => title
|
54
|
+
add_child build(:folder, attributes, &block)
|
55
55
|
end
|
56
56
|
# Builds an alias with given attributes and add it.
|
57
|
-
def
|
58
|
-
|
59
|
-
|
57
|
+
def add_alias(ref)
|
58
|
+
node = Nokogiri::XML::Node.new 'alias', document
|
59
|
+
node.ref = (Entry === ref) ? ref.id : ref.to_s
|
60
60
|
|
61
|
-
add_child
|
61
|
+
add_child node
|
62
62
|
end
|
63
63
|
# Builds a saperator with given attributes and add it.
|
64
64
|
def add_separator
|
@@ -67,18 +67,21 @@ module Nokogiri::Decorators::XBEL
|
|
67
67
|
|
68
68
|
protected
|
69
69
|
|
70
|
-
def
|
71
|
-
|
70
|
+
def generate_id
|
71
|
+
"#{ id }#{ document.div_id_er }" << xpath('./bookmark | ./folder').
|
72
72
|
inject(0) { |next_id, child|
|
73
73
|
succ_num_id = child.id[/(\d+)$/, 1].to_i.succ
|
74
74
|
succ_num_id > next_id ? succ_num_id : next_id
|
75
75
|
}.to_s
|
76
|
+
end
|
76
77
|
|
77
|
-
|
78
|
-
|
78
|
+
def add_child(node)
|
79
|
+
if Entry === node
|
80
|
+
node.id ||= generate_id
|
81
|
+
node.added = Time.now
|
79
82
|
end
|
80
83
|
|
81
|
-
|
84
|
+
super
|
82
85
|
end
|
83
86
|
|
84
87
|
end
|
data/lib/xbel.rb
CHANGED
@@ -5,11 +5,22 @@ require 'nokogiri/decorators/xbel'
|
|
5
5
|
|
6
6
|
class XBEL < Nokogiri::XML::Document
|
7
7
|
extend Forwardable
|
8
|
-
def_delegators :root,
|
8
|
+
def_delegators :root,
|
9
|
+
:title, :title=,
|
10
|
+
:desc, :desc=,
|
11
|
+
:id, :id=
|
12
|
+
|
13
|
+
attr_accessor :div_id_er
|
14
|
+
|
15
|
+
TEMPLATE = %Q'<!DOCTYPE xbel PUBLIC "+//IDN python.org//DTD XML Bookmark Exchange Language 1.0//EN//XML" "http://www.python.org/topics/xml/dtds/xbel-1.0.dtd"><xbel version="1.0" id="0"></xbel>'
|
16
|
+
DIV_ID_ER = '_'
|
9
17
|
|
10
18
|
# Returns an instance of XBEL.
|
11
|
-
def self.new(
|
12
|
-
|
19
|
+
def self.new(attributes = {})
|
20
|
+
xbel = parse TEMPLATE
|
21
|
+
xbel.attributes = attributes
|
22
|
+
|
23
|
+
xbel
|
13
24
|
end
|
14
25
|
|
15
26
|
# Reads file at <tt>path</tt> into <tt>parse</tt>.
|
@@ -24,6 +35,8 @@ class XBEL < Nokogiri::XML::Document
|
|
24
35
|
super
|
25
36
|
decorators(Nokogiri::XML::Node) << Nokogiri::Decorators::XBEL
|
26
37
|
decorate!
|
38
|
+
|
39
|
+
@div_id_er = DIV_ID_ER
|
27
40
|
end
|
28
41
|
|
29
42
|
# Returns node with given <tt>id</tt>.
|
@@ -31,6 +44,13 @@ class XBEL < Nokogiri::XML::Document
|
|
31
44
|
root.at("//*[@id='#{ id }']")
|
32
45
|
end
|
33
46
|
|
47
|
+
def attributes=(attributes)
|
48
|
+
version = attributes.delete(:version) and self.version = version
|
49
|
+
div_id_er = attributes.delete(:div_id_er) and self.div_id_er = div_id_er
|
50
|
+
|
51
|
+
root.attributes = attributes
|
52
|
+
end
|
53
|
+
|
34
54
|
# Returns an array of version numbers.
|
35
55
|
def version
|
36
56
|
root.attribute('version').value.split('.').map { |n| n.to_i }
|
data/test/test_xbel.rb
CHANGED
@@ -1,142 +1,172 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
|
-
context 'New XBEL' do
|
4
|
-
|
5
|
-
asserts 'version' do
|
6
|
-
XBEL.new.version
|
7
|
-
end.equals [1, 0]
|
8
|
-
asserts 'user defined version' do
|
9
|
-
XBEL.new(2, 2).version
|
10
|
-
end.equals [2, 2]
|
11
|
-
asserts 'set version' do
|
12
|
-
xbel = XBEL.new
|
13
|
-
xbel.version = 1, 1
|
14
|
-
|
15
|
-
xbel.version
|
16
|
-
end.equals [1, 1]
|
17
|
-
should 'be empty' do
|
18
|
-
XBEL.new.root.content.empty?
|
19
|
-
end
|
20
|
-
|
21
|
-
end
|
22
|
-
|
23
3
|
context 'XBEL' do
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
4
|
+
setup { XBEL }
|
5
|
+
|
6
|
+
context 'build with defaults' do
|
7
|
+
setup { topic.new }
|
8
|
+
|
9
|
+
asserts 'version' do
|
10
|
+
topic.version
|
11
|
+
end.equals [1, 0]
|
12
|
+
asserts 'version set' do
|
13
|
+
topic.version = 1, 1
|
14
|
+
topic.version
|
15
|
+
end.equals [1, 1]
|
16
|
+
should 'be empty' do
|
17
|
+
topic.root.content.empty?
|
18
|
+
end
|
19
|
+
should 'have an id divider' do
|
20
|
+
String === topic.div_id_er and
|
21
|
+
topic.div_id_er.length > 0
|
22
|
+
end
|
23
|
+
end
|
24
|
+
context 'built with attributes' do
|
25
|
+
setup { topic.new :version => [2, 2], :div_id_er => '/', :id => 'custom' }
|
26
|
+
|
27
|
+
asserts 'user defined version' do
|
28
|
+
topic.version
|
29
|
+
end.equals [2, 2]
|
30
|
+
asserts 'div_id_er' do
|
31
|
+
topic.div_id_er
|
32
|
+
end.equals '/'
|
33
|
+
asserts 'id' do
|
34
|
+
topic.id
|
35
|
+
end.equals 'custom'
|
36
|
+
|
37
|
+
asserts 'id of added folder' do
|
38
|
+
topic.root.add_folder('foo').id
|
39
|
+
end.equals 'custom/0'
|
28
40
|
end
|
29
41
|
|
30
|
-
|
42
|
+
context 'loaded from wikipedia.xbel' do
|
43
|
+
setup do
|
44
|
+
root = Pathname.new File.dirname(__FILE__)
|
45
|
+
topic.open root.join('wikipedia.xbel')
|
46
|
+
end
|
31
47
|
|
32
|
-
|
33
|
-
should('delegate title accessor to root') do
|
34
|
-
topic.title = 'Bookmarks!'
|
48
|
+
asserts('version') { topic.version }.equals [1, 0]
|
35
49
|
|
36
|
-
|
37
|
-
|
38
|
-
|
50
|
+
asserts('title') { topic.title }.equals 'Lesezeichen!'
|
51
|
+
should('delegate title accessor to root') do
|
52
|
+
topic.title = 'Bookmarks!'
|
39
53
|
|
40
|
-
|
41
|
-
|
42
|
-
should('be an alias') { topic.alias? }
|
43
|
-
|
44
|
-
should('have a reference') do
|
45
|
-
topic.ref and
|
46
|
-
topic.ref == topic.reference
|
54
|
+
topic.title == topic.root.title and
|
55
|
+
topic.title == 'Bookmarks!'
|
47
56
|
end
|
48
|
-
end
|
49
57
|
|
50
|
-
|
51
|
-
|
52
|
-
|
58
|
+
context 'Alias' do
|
59
|
+
setup { topic.root.aliases.first }
|
60
|
+
should('be an alias') { topic.alias? }
|
53
61
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
should('return bookmarks') do
|
59
|
-
not topic.bookmarks.any? { |b| b.name != 'bookmark' }
|
60
|
-
end
|
61
|
-
should('return aliases') do
|
62
|
-
not topic.aliases.any? { |b| b.name != 'alias' }
|
62
|
+
should('have a reference') do
|
63
|
+
topic.ref and
|
64
|
+
topic.ref == topic.reference
|
65
|
+
end
|
63
66
|
end
|
64
|
-
|
65
|
-
|
67
|
+
|
68
|
+
context 'root' do
|
69
|
+
setup { topic.root }
|
70
|
+
context 'new Bookmark' do
|
71
|
+
setup do
|
72
|
+
topic.add_bookmark "boof's xbel", 'http://www.github.com/boof/xbel',
|
73
|
+
:description => 'Ruby API for XBEL based on Nokogiri.'
|
74
|
+
end
|
75
|
+
asserts('next id') { topic.id }.equals 'test_2'
|
76
|
+
end
|
66
77
|
end
|
67
78
|
|
68
|
-
context '
|
69
|
-
setup { topic
|
70
|
-
should('be a
|
79
|
+
context 'Folder' do
|
80
|
+
setup { topic[:test_1] }
|
81
|
+
should('be a folder') { topic.folder? }
|
71
82
|
|
72
|
-
asserts('
|
83
|
+
asserts('title') { topic.title }.equals 'Wiki'
|
84
|
+
asserts('entries names') do
|
85
|
+
topic.entries.map { |e| e.name }.uniq.sort
|
86
|
+
end.equals %w[ alias bookmark folder separator ]
|
87
|
+
should('return bookmarks') do
|
88
|
+
not topic.bookmarks.any? { |b| b.name != 'bookmark' }
|
89
|
+
end
|
90
|
+
should('return aliases') do
|
91
|
+
not topic.aliases.any? { |b| b.name != 'alias' }
|
92
|
+
end
|
93
|
+
should('return folders') do
|
94
|
+
not topic.folders.any? { |b| b.name != 'folder' }
|
95
|
+
end
|
73
96
|
|
74
|
-
|
75
|
-
|
76
|
-
topic.
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
97
|
+
context 'Bookmark' do
|
98
|
+
setup { topic.bookmarks.first }
|
99
|
+
should('be a bookmark') { topic.bookmark? }
|
100
|
+
|
101
|
+
asserts('modified') { topic.modified }.kind_of Date
|
102
|
+
|
103
|
+
asserts('visited') { topic.visited }.kind_of Date
|
104
|
+
asserts('visit') do
|
105
|
+
topic.visit
|
106
|
+
topic.visited
|
107
|
+
end.equals Date.today
|
108
|
+
end
|
109
|
+
context 'new Bookmark' do
|
110
|
+
setup do
|
111
|
+
topic.add_bookmark "boof's xbel", 'http://www.github.com/boof/xbel',
|
112
|
+
:description => 'Ruby API for XBEL based on Nokogiri.'
|
113
|
+
end
|
114
|
+
should('be a bookmark') { topic.bookmark? }
|
115
|
+
|
116
|
+
asserts('added') { topic.added }.equals Date.today
|
117
|
+
asserts('title') { topic.title }.equals 'boof\'s xbel'
|
118
|
+
asserts('next id') { topic.id }.equals 'test_1_4'
|
119
|
+
asserts('href') { topic.href }.
|
120
|
+
equals 'http://www.github.com/boof/xbel'
|
121
|
+
asserts('description') { topic.description }.
|
122
|
+
equals 'Ruby API for XBEL based on Nokogiri.'
|
84
123
|
end
|
85
|
-
should('be a bookmark') { topic.bookmark? }
|
86
124
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
asserts('href') { topic.href }.
|
91
|
-
equals 'http://www.github.com/boof/xbel'
|
92
|
-
asserts('description') { topic.description }.
|
93
|
-
equals 'Ruby API for XBEL based on Nokogiri.'
|
94
|
-
end
|
125
|
+
context 'new Folder' do
|
126
|
+
setup { topic.add_folder 'sub', :desc => 'desc' }
|
127
|
+
should('be a folder') { topic.folder? }
|
95
128
|
|
96
|
-
|
97
|
-
|
98
|
-
|
129
|
+
asserts('added') { topic.added }.equals Date.today
|
130
|
+
asserts('title') { topic.title }.equals 'sub'
|
131
|
+
asserts('next id') { topic.id }.equals 'test_1_4'
|
132
|
+
asserts('desc') { topic.desc }.equals 'desc'
|
133
|
+
end
|
99
134
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
asserts('desc') { topic.desc }.equals 'desc'
|
104
|
-
end
|
135
|
+
context 'new Alias' do
|
136
|
+
setup { topic.add_alias topic }
|
137
|
+
should('be an alias') { topic.alias? }
|
105
138
|
|
106
|
-
|
107
|
-
|
108
|
-
|
139
|
+
should('reference its folder') { topic.entry == topic.parent }
|
140
|
+
should('set reference by entry') do
|
141
|
+
topic.entry = topic.document[:test_1_3]
|
142
|
+
topic.ref == 'test_1_3'
|
143
|
+
end
|
144
|
+
end
|
109
145
|
|
110
|
-
|
111
|
-
|
112
|
-
topic.
|
113
|
-
topic.ref == 'b1'
|
146
|
+
context 'Separator' do
|
147
|
+
setup { topic.entries.find { |e| e.name == 'separator' } }
|
148
|
+
asserts('to_s') { topic.to_s }.equals ' '
|
114
149
|
end
|
115
|
-
end
|
116
150
|
|
117
|
-
context 'Separator' do
|
118
|
-
setup { topic.entries.find { |e| e.name == 'separator' } }
|
119
|
-
asserts('to_s') { topic.to_s }.equals ' '
|
120
151
|
end
|
121
152
|
|
122
|
-
|
153
|
+
context 'Bookmark b0' do
|
154
|
+
setup { topic[:test_1_1] }
|
155
|
+
should('be a bookmark') { topic.bookmark? }
|
123
156
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
context 'Info' do
|
129
|
-
setup { topic.info }
|
130
|
-
should('be a hash') { Hash === topic }
|
157
|
+
context 'Info' do
|
158
|
+
setup { topic.info }
|
159
|
+
should('be a hash') { Hash === topic }
|
131
160
|
|
132
|
-
|
133
|
-
|
134
|
-
|
161
|
+
context 'metadata for xbel' do
|
162
|
+
setup { topic[:xbel] if topic }
|
163
|
+
should('be a node') { Nokogiri::XML::Node === topic }
|
135
164
|
|
136
|
-
|
165
|
+
should('be have an alias') { not topic.at('./alias').nil? }
|
166
|
+
end
|
137
167
|
end
|
138
|
-
end
|
139
168
|
|
169
|
+
end
|
140
170
|
end
|
141
171
|
|
142
172
|
end
|
data/test/wikipedia.xbel
CHANGED
@@ -2,27 +2,27 @@
|
|
2
2
|
<!DOCTYPE xbel
|
3
3
|
PUBLIC "+//IDN python.org//DTD XML Bookmark Exchange Language 1.0//EN//XML"
|
4
4
|
"http://www.python.org/topics/xml/dtds/xbel-1.0.dtd">
|
5
|
-
<xbel version="1.0">
|
5
|
+
<xbel version="1.0" id="test">
|
6
6
|
<title>Lesezeichen!</title>
|
7
7
|
<desc>Lernen von XBEL am Beispiel von zwei Lesezeichen und einer Verknüpfung</desc>
|
8
|
-
<folder id="
|
8
|
+
<folder id="test_1" added="2007-11-10">
|
9
9
|
<title>Wiki</title>
|
10
10
|
<desc>Webseiten von Autoren-Gemeinschaften</desc>
|
11
|
-
<bookmark href="http://wikimediafoundation.org/" id="
|
11
|
+
<bookmark href="http://wikimediafoundation.org/" id="test_1_1" added="2007-11-11" modified="2007-11-14" visited="2007-11-14">
|
12
12
|
<info>
|
13
13
|
<metadata owner="xbel">
|
14
|
-
<alias ref="
|
14
|
+
<alias ref="test_1" />
|
15
15
|
</metadata>
|
16
16
|
</info>
|
17
17
|
<title>Wikimedia Foundation</title>
|
18
18
|
</bookmark>
|
19
|
-
<alias ref="
|
19
|
+
<alias ref="test_1_1" />
|
20
20
|
<separator />
|
21
|
-
<bookmark href="http://de.wikipedia.org/" id="
|
21
|
+
<bookmark href="http://de.wikipedia.org/" id="test_1_2" added="2007-11-11" modified="2007-11-14" visited="2007-12-27">
|
22
22
|
<title>Wikipedia</title>
|
23
23
|
</bookmark>
|
24
|
-
<folder id="
|
24
|
+
<folder id="test_1_3"></folder>
|
25
25
|
</folder>
|
26
26
|
<separator />
|
27
|
-
<alias ref="
|
27
|
+
<alias ref="test_1_2" />
|
28
28
|
</xbel>
|
data/xbel.gemspec
CHANGED