nanoc3 3.0.2 → 3.0.3

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/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