nanoc3 3.0.2 → 3.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/NEWS.rdoc CHANGED
@@ -1,5 +1,17 @@
1
1
  = nanoc News
2
2
 
3
+ == 3.0.3
4
+
5
+ * The Blogging helper now properly handles item reps without paths
6
+ * The relativize_paths filter now only operates inside tags
7
+ * The autocompiler now handles escaped paths
8
+ * The link_to and tagging helpers now output escaped HTML
9
+ * Fixed played_at attribute assignment in Last.fm data source for tracks
10
+ playing now and added a now_playing attribute [Nicky Peeters]
11
+ * The filesystem_* data sources can now handle dots in identifiers
12
+ * Required enumerator to make sure #enum_with_index always works
13
+ * Array#stringify_keys now properly recurses
14
+
3
15
  == 3.0.2
4
16
 
5
17
  * Children-only identifier patterns no longer erroneously also match parent
@@ -3,7 +3,7 @@
3
3
  module Nanoc3
4
4
 
5
5
  # The current nanoc version.
6
- VERSION = '3.0.2'
6
+ VERSION = '3.0.3'
7
7
 
8
8
  end
9
9
 
@@ -177,7 +177,7 @@ module Nanoc3
177
177
 
178
178
  # Write if rep is routed
179
179
  rep.write unless rep.raw_path.nil?
180
-
180
+ ensure
181
181
  # Stop
182
182
  Nanoc3::NotificationCenter.post(:visit_ended, rep.item)
183
183
  Nanoc3::NotificationCenter.post(:compilation_ended, rep)
@@ -2,15 +2,17 @@
2
2
 
3
3
  module Nanoc3::ArrayExtensions
4
4
 
5
+ # Returns a new array where all items' keys are recursively converted to symbols by calling #symbolize_keys.
5
6
  def symbolize_keys
6
7
  inject([]) do |array, element|
7
8
  array + [ element.respond_to?(:symbolize_keys) ? element.symbolize_keys : element ]
8
9
  end
9
10
  end
10
11
 
12
+ # Returns a new array where all items' keys are recursively converted to strings by calling #stringify_keys.
11
13
  def stringify_keys
12
14
  inject([]) do |array, element|
13
- array + [ element.respond_to?(:stringify_keys) ? element.symbolize_keys : element ]
15
+ array + [ element.respond_to?(:stringify_keys) ? element.stringify_keys : element ]
14
16
  end
15
17
  end
16
18
 
@@ -32,6 +32,7 @@ module Nanoc3::DataSources
32
32
  @items ||= begin
33
33
  require 'json'
34
34
  require 'time'
35
+ require 'enumerator'
35
36
 
36
37
  # Get data
37
38
  @http_client ||= Nanoc3::Extra::CHiCk::Client.new
@@ -90,9 +90,9 @@ module Nanoc3::DataSources
90
90
 
91
91
  # Get actual identifier
92
92
  if filename =~ /\/index\.[^\/]+$/
93
- identifier = filename.sub(/^content/, '').sub(/index\.[^\/]+$/, '') + '/'
93
+ identifier = filename.sub(/^content/, '').sub(/index\.[^\/\.]+$/, '') + '/'
94
94
  else
95
- identifier = filename.sub(/^content/, '').sub(/\.[^\/]+$/, '') + '/'
95
+ identifier = filename.sub(/^content/, '').sub(/\.[^\/\.]+$/, '') + '/'
96
96
  end
97
97
 
98
98
  # Get mtime
@@ -110,9 +110,9 @@ module Nanoc3::DataSources
110
110
 
111
111
  # Get actual identifier
112
112
  if filename =~ /\/index\.[^\/]+$/
113
- identifier = filename.sub(/^layouts/, '').sub(/index\.[^\/]+$/, '') + '/'
113
+ identifier = filename.sub(/^layouts/, '').sub(/index\.[^\/\.]+$/, '') + '/'
114
114
  else
115
- identifier = filename.sub(/^layouts/, '').sub(/\.[^\/]+$/, '') + '/'
115
+ identifier = filename.sub(/^layouts/, '').sub(/\.[^\/\.]+$/, '') + '/'
116
116
  end
117
117
 
118
118
  # Get mtime
@@ -208,7 +208,9 @@ module Nanoc3::DataSources
208
208
  # '.rej' or '.bak')
209
209
  def content_filename_for_meta_filename(meta_filename)
210
210
  # Find all files
211
- filenames = Dir[meta_filename.sub(/\.yaml$/, '.*')]
211
+ base_filename = File.basename(meta_filename, '.yaml')
212
+ dirname = File.dirname(meta_filename)
213
+ filenames = Dir.entries(dirname).select { |f| f =~ /#{base_filename}\.[^.]+$/ }.map { |f| "#{dirname}/#{f}" }
212
214
 
213
215
  # Reject meta files
214
216
  filenames.reject! { |f| f =~ /\.yaml$/ }
@@ -36,6 +36,7 @@ module Nanoc3::DataSources
36
36
  require 'json'
37
37
  require 'time'
38
38
  require 'uri'
39
+ require 'enumerator'
39
40
 
40
41
  # Check configuration
41
42
  if self.config[:username].nil?
@@ -80,6 +81,16 @@ module Nanoc3::DataSources
80
81
 
81
82
  # Build data
82
83
  content = ''
84
+
85
+ # Handle track dates
86
+ if raw_item['@attr'] && raw_item['@attr']['nowplaying'] == 'true'
87
+ track_played_at = Time.now
88
+ now_playing = true
89
+ else
90
+ played_at = Time.parse(raw_item['date']['#text'])
91
+ now_playing = false
92
+ end
93
+
83
94
  attributes = {
84
95
  :name => raw_item['name'],
85
96
  :artist => {
@@ -87,7 +98,8 @@ module Nanoc3::DataSources
87
98
  :url => raw_artist_info['url']
88
99
  },
89
100
  :url => raw_item['url'],
90
- :played_at => Time.parse(raw_item['date']['#text'])
101
+ :played_at => track_played_at,
102
+ :now_playing => now_playing
91
103
  }
92
104
  identifier = "/#{i}/"
93
105
  mtime = nil
@@ -0,0 +1,104 @@
1
+ # encoding: utf-8
2
+
3
+ module Nanoc3::DataSources
4
+
5
+ # Nanoc3::DataSources::LastFM provides data about recently played tracks
6
+ # from from a single Last.fm user as items (Nanoc3::Item instances).
7
+ #
8
+ # The configuration must have a "username" attribute containing the username
9
+ # of the account from which to fetch the data, and an "api_key" attribute
10
+ # containing the API key (which can be obtained from the Last.fm site).
11
+ #
12
+ # The items returned by this data source will be mounted at {root}/{id},
13
+ # where +id+ is a sequence number that is not necessarily unique for this
14
+ # bookmark (because delicious.com unfortunately does not provide unique IDs
15
+ # for each track).
16
+ #
17
+ # The items returned by this data source will have the following attributes:
18
+ #
19
+ # +:name+:: The name of the track.
20
+ #
21
+ # +played_at+:: The timestamp when the track was played (a Time instance).
22
+ #
23
+ # +url+:: The Last.fm URL corresponding to the track (a String instance).
24
+ #
25
+ # +artist+:: A hash containing information about the track's artist.
26
+ #
27
+ # The +artist+ hash consists of the following keys:
28
+ #
29
+ # +name+:: The name of the artist.
30
+ #
31
+ # +url+:: The Last.fm URL corresponding to the artist (a String instance).
32
+ class LastFM < Nanoc3::DataSource
33
+
34
+ def items
35
+ @items ||= begin
36
+ require 'json'
37
+ require 'time'
38
+ require 'uri'
39
+ require 'enumerator'
40
+
41
+ # Check configuration
42
+ if self.config[:username].nil?
43
+ raise RuntimeError, "LastFM data source requires a username in the configuration"
44
+ end
45
+ if self.config[:api_key].nil?
46
+ raise RuntimeError, "LastFM data source requires an API key in the configuration"
47
+ end
48
+
49
+ # Get data
50
+ @http_client ||= Nanoc3::Extra::CHiCk::Client.new
51
+ status, headers, data = *@http_client.get(
52
+ 'http://ws.audioscrobbler.com/2.0/' +
53
+ '?method=user.getRecentTracks' +
54
+ '&format=json' +
55
+ '&user=' + URI.escape(self.config[:username]) +
56
+ '&api_key=' + URI.escape(self.config[:api_key])
57
+ )
58
+
59
+ # Parse as JSON
60
+ parsed_data = JSON.parse(data)
61
+ raw_items = parsed_data['recenttracks']['track']
62
+
63
+ # Convert to items
64
+ raw_items.enum_with_index.map do |raw_item, i|
65
+ # Get artist data
66
+ artist_status, artist_headers, artist_data = *@http_client.get(
67
+ 'http://ws.audioscrobbler.com/2.0/' +
68
+ '?method=artist.getInfo' +
69
+ '&format=json' +
70
+ (
71
+ raw_item['artist']['mbid'].empty? ?
72
+ '&artist=' + URI.escape(raw_item['artist']['#text']) :
73
+ '&mbid=' + URI.escape(raw_item['artist']['mbid'])
74
+ ) +
75
+ '&api_key=' + URI.escape(self.config[:api_key])
76
+ )
77
+
78
+ # Parse as JSON
79
+ parsed_artist_data = JSON.parse(artist_data)
80
+ raw_artist_info = parsed_artist_data['artist']
81
+
82
+ # Build data
83
+ content = ''
84
+ attributes = {
85
+ :name => raw_item['name'],
86
+ :artist => {
87
+ :name => raw_artist_info['name'],
88
+ :url => raw_artist_info['url']
89
+ },
90
+ :url => raw_item['url'],
91
+ :played_at => Time.parse(raw_item['date']['#text'])
92
+ }
93
+ identifier = "/#{i}/"
94
+ mtime = nil
95
+
96
+ # Build item
97
+ Nanoc3::Item.new(content, attributes, identifier, mtime)
98
+ end
99
+ end
100
+ end
101
+
102
+ end
103
+
104
+ end
@@ -22,6 +22,7 @@ module Nanoc3::DataSources
22
22
  @item ||= begin
23
23
  require 'json'
24
24
  require 'time'
25
+ require 'enumerator'
25
26
 
26
27
  # Get data
27
28
  @http_client ||= Nanoc3::Extra::CHiCk::Client.new
@@ -27,7 +27,7 @@ module Nanoc3::Extra
27
27
  build_site
28
28
 
29
29
  # Find rep
30
- path = env['PATH_INFO']
30
+ path = Rack::Utils::unescape(env['PATH_INFO'])
31
31
  reps = site.items.map { |i| i.reps }.flatten
32
32
  rep = reps.find { |r| r.path == path }
33
33
 
@@ -13,8 +13,8 @@ module Nanoc3::Filters
13
13
  # Filter
14
14
  case params[:type]
15
15
  when :html
16
- content.gsub(/(src|href)=(['"]?)(\/.+?)\2([ >])/) do
17
- $1 + '=' + $2 + relative_path_to($3) + $2 + $4
16
+ content.gsub(/(<[^>]+\s+(src|href))=(['"]?)(\/.+?)\3([ >])/) do
17
+ $1 + '=' + $3 + relative_path_to($4) + $3 + $5
18
18
  end
19
19
  when :css
20
20
  content.gsub(/url\((['"]?)(\/.+?)\1\)/) do
@@ -173,6 +173,10 @@ module Nanoc3::Helpers
173
173
 
174
174
  # Add articles
175
175
  sorted_relevant_articles.each do |a|
176
+ # Get URL
177
+ url = url_for(a)
178
+ next if url.nil?
179
+
176
180
  xml.entry do
177
181
  # Add primary attributes
178
182
  xml.id atom_tag_for(a)
@@ -183,7 +187,7 @@ module Nanoc3::Helpers
183
187
  xml.updated a.mtime.to_iso8601_time
184
188
 
185
189
  # Add link
186
- xml.link(:rel => 'alternate', :href => url_for(a))
190
+ xml.link(:rel => 'alternate', :href => url)
187
191
 
188
192
  # Add content
189
193
  summary = excerpt_proc.call(a)
@@ -204,7 +208,12 @@ module Nanoc3::Helpers
204
208
  raise RuntimeError.new('Cannot build Atom feed: site configuration has no base_url')
205
209
  end
206
210
 
207
- @site.config[:base_url] + (item[:custom_path_in_feed] || item.reps[0].path)
211
+ # Get path
212
+ path = item[:custom_path_in_feed] || item.reps[0].path
213
+ return nil if path.nil?
214
+
215
+ # Build URL
216
+ @site.config[:base_url] + path
208
217
  end
209
218
 
210
219
  # Returns the URL of the feed. It will return the custom feed URL if set,
@@ -44,7 +44,7 @@ module Nanoc3::Helpers
44
44
  end
45
45
 
46
46
  # Create link
47
- "<a #{attributes}href=\"#{path}\">#{text}</a>"
47
+ "<a #{attributes}href=\"#{h path}\">#{text}</a>"
48
48
  end
49
49
 
50
50
  # Creates a HTML link using link_to, except when the linked item is the
@@ -13,6 +13,9 @@ module Nanoc3::Helpers
13
13
  # include Nanoc3::Helpers::Tagging
14
14
  module Tagging
15
15
 
16
+ require 'nanoc3/helpers/html_escape'
17
+ include Nanoc3::Helpers::HTMLEscape
18
+
16
19
  # Returns a formatted list of tags for the given item as a string. Several
17
20
  # parameters allow customization:
18
21
  #
@@ -50,7 +53,7 @@ module Nanoc3::Helpers
50
53
  # +base_url+:: The URL to which the tag will be appended to construct the
51
54
  # link URL. This URL must have a trailing slash.
52
55
  def link_for_tag(tag, base_url)
53
- %[<a href="#{base_url}#{tag}" rel="tag">#{tag}</a>]
56
+ %[<a href="#{h base_url}#{h tag}" rel="tag">#{h tag}</a>]
54
57
  end
55
58
 
56
59
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nanoc3
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.2
4
+ version: 3.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Denis Defreyne
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-11-07 00:00:00 +01:00
12
+ date: 2010-01-07 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -73,6 +73,7 @@ files:
73
73
  - lib/nanoc3/data_sources/filesystem_common.rb
74
74
  - lib/nanoc3/data_sources/filesystem_compact.rb
75
75
  - lib/nanoc3/data_sources/last_fm.rb
76
+ - lib/nanoc3/data_sources/last_fm.rb.orig
76
77
  - lib/nanoc3/data_sources/twitter.rb
77
78
  - lib/nanoc3/data_sources.rb
78
79
  - lib/nanoc3/extra/auto_compiler.rb