nanoc3 3.0.6 → 3.0.7

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,9 @@
1
1
  = nanoc News
2
2
 
3
+ == 3.0.7
4
+
5
+ * Fixed bug which could cause layout rules not be matched in order
6
+
3
7
  == 3.0.6
4
8
 
5
9
  * Error checking in `filesystem_combined` has been improved [Brian Candler]
@@ -30,7 +30,7 @@ module Nanoc3
30
30
 
31
31
  @item_compilation_rules = []
32
32
  @item_routing_rules = []
33
- @layout_filter_mapping = {}
33
+ @layout_filter_mapping = OrderedHash.new
34
34
  end
35
35
 
36
36
  # Compiles (part of) the site and writes out the compiled item
@@ -0,0 +1,200 @@
1
+
2
+ # AUTHOR
3
+ # jan molic /mig/at/1984/dot/cz/
4
+ #
5
+ # DESCRIPTION
6
+ # Hash with preserved order and some array-like extensions
7
+ # Public domain.
8
+ #
9
+ # THANKS
10
+ # Andrew Johnson for his suggestions and fixes of Hash[],
11
+ # merge, to_a, inspect and shift
12
+ class OrderedHash < ::Hash
13
+ attr_accessor :order
14
+
15
+ class << self
16
+ def [] *args
17
+ hsh = OrderedHash.new
18
+ if Hash === args[0]
19
+ hsh.replace args[0]
20
+ elsif (args.size % 2) != 0
21
+ raise ArgumentError, "odd number of elements for Hash"
22
+ else
23
+ 0.step(args.size - 1, 2) do |a|
24
+ b = a + 1
25
+ hsh[args[a]] = args[b]
26
+ end
27
+ end
28
+ hsh
29
+ end
30
+ end
31
+ def initialize(*a, &b)
32
+ super
33
+ @order = []
34
+ end
35
+ def store_only a,b
36
+ store a,b
37
+ end
38
+ alias orig_store store
39
+ def store a,b
40
+ @order.push a unless has_key? a
41
+ super a,b
42
+ end
43
+ alias []= store
44
+ def == hsh2
45
+ return false if @order != hsh2.order
46
+ super hsh2
47
+ end
48
+ def clear
49
+ @order = []
50
+ super
51
+ end
52
+ def delete key
53
+ @order.delete key
54
+ super
55
+ end
56
+ def each_key
57
+ @order.each { |k| yield k }
58
+ self
59
+ end
60
+ def each_value
61
+ @order.each { |k| yield self[k] }
62
+ self
63
+ end
64
+ def each
65
+ @order.each { |k| yield k,self[k] }
66
+ self
67
+ end
68
+ alias each_pair each
69
+ def delete_if
70
+ @order.clone.each { |k|
71
+ delete k if yield(k)
72
+ }
73
+ self
74
+ end
75
+ def values
76
+ ary = []
77
+ @order.each { |k| ary.push self[k] }
78
+ ary
79
+ end
80
+ def keys
81
+ @order
82
+ end
83
+ def first
84
+ {@order.first => self[@order.first]}
85
+ end
86
+ def last
87
+ {@order.last => self[@order.last]}
88
+ end
89
+ def invert
90
+ hsh2 = Hash.new
91
+ @order.each { |k| hsh2[self[k]] = k }
92
+ hsh2
93
+ end
94
+ def reject &block
95
+ self.dup.delete_if &block
96
+ end
97
+ def reject! &block
98
+ hsh2 = reject &block
99
+ self == hsh2 ? nil : hsh2
100
+ end
101
+ def replace hsh2
102
+ @order = hsh2.keys
103
+ super hsh2
104
+ end
105
+ def shift
106
+ key = @order.first
107
+ key ? [key,delete(key)] : super
108
+ end
109
+ def unshift k,v
110
+ unless self.include? k
111
+ @order.unshift k
112
+ orig_store(k,v)
113
+ true
114
+ else
115
+ false
116
+ end
117
+ end
118
+ def push k,v
119
+ unless self.include? k
120
+ @order.push k
121
+ orig_store(k,v)
122
+ true
123
+ else
124
+ false
125
+ end
126
+ end
127
+ def pop
128
+ key = @order.last
129
+ key ? [key,delete(key)] : nil
130
+ end
131
+ def to_a
132
+ ary = []
133
+ each { |k,v| ary << [k,v] }
134
+ ary
135
+ end
136
+ def to_s
137
+ self.to_a.to_s
138
+ end
139
+ def inspect
140
+ ary = []
141
+ each {|k,v| ary << k.inspect + "=>" + v.inspect}
142
+ '{' + ary.join(", ") + '}'
143
+ end
144
+ def update hsh2
145
+ hsh2.each { |k,v| self[k] = v }
146
+ self
147
+ end
148
+ alias :merge! update
149
+ def merge hsh2
150
+ self.dup update(hsh2)
151
+ end
152
+ def select
153
+ ary = []
154
+ each { |k,v| ary << [k,v] if yield k,v }
155
+ ary
156
+ end
157
+ def class
158
+ Hash
159
+ end
160
+ def __class__
161
+ OrderedHash
162
+ end
163
+
164
+ attr_accessor "to_yaml_style"
165
+ def yaml_inline= bool
166
+ if respond_to?("to_yaml_style")
167
+ self.to_yaml_style = :inline
168
+ else
169
+ unless defined? @__yaml_inline_meth
170
+ @__yaml_inline_meth =
171
+ lambda {|opts|
172
+ YAML::quick_emit(object_id, opts) {|emitter|
173
+ emitter << '{ ' << map{|kv| kv.join ': '}.join(', ') << ' }'
174
+ }
175
+ }
176
+ class << self
177
+ def to_yaml opts = {}
178
+ begin
179
+ @__yaml_inline ? @__yaml_inline_meth[ opts ] : super
180
+ rescue
181
+ @to_yaml_style = :inline
182
+ super
183
+ end
184
+ end
185
+ end
186
+ end
187
+ end
188
+ @__yaml_inline = bool
189
+ end
190
+ def yaml_inline!() self.yaml_inline = true end
191
+
192
+ def each_with_index
193
+ @order.each_with_index { |k, index| yield k, self[k], index }
194
+ self
195
+ end
196
+ end # class OrderedHash
197
+
198
+ def OrderedHash(*a, &b)
199
+ OrderedHash.new(*a, &b)
200
+ end
data/lib/nanoc3/base.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  module Nanoc3
4
4
 
5
5
  require 'nanoc3/base/core_ext'
6
+ require 'nanoc3/base/ordered_hash'
6
7
 
7
8
  autoload 'CodeSnippet', 'nanoc3/base/code_snippet'
8
9
  autoload 'Compiler', 'nanoc3/base/compiler'
data/lib/nanoc3.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  module Nanoc3
4
4
 
5
5
  # The current nanoc version.
6
- VERSION = '3.0.6'
6
+ VERSION = '3.0.7'
7
7
 
8
8
  end
9
9
 
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.6
4
+ version: 3.0.7
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: 2010-01-18 00:00:00 +01:00
12
+ date: 2010-01-30 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -35,7 +35,6 @@ files:
35
35
  - bin/nanoc3
36
36
  - lib/nanoc3/base/code_snippet.rb
37
37
  - lib/nanoc3/base/compiler.rb
38
- - lib/nanoc3/base/compiler.rb.orig
39
38
  - lib/nanoc3/base/compiler_dsl.rb
40
39
  - lib/nanoc3/base/core_ext/array.rb
41
40
  - lib/nanoc3/base/core_ext/hash.rb
@@ -49,6 +48,7 @@ files:
49
48
  - lib/nanoc3/base/item_rep.rb
50
49
  - lib/nanoc3/base/layout.rb
51
50
  - lib/nanoc3/base/notification_center.rb
51
+ - lib/nanoc3/base/ordered_hash.rb
52
52
  - lib/nanoc3/base/plugin.rb
53
53
  - lib/nanoc3/base/preprocessor_context.rb
54
54
  - lib/nanoc3/base/rule.rb
@@ -73,7 +73,6 @@ 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
77
76
  - lib/nanoc3/data_sources/twitter.rb
78
77
  - lib/nanoc3/data_sources.rb
79
78
  - lib/nanoc3/extra/auto_compiler.rb
@@ -1,250 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module Nanoc3
4
-
5
- # Nanoc3::Compiler is responsible for compiling a site's item
6
- # representations.
7
- class Compiler
8
-
9
- # The compilation stack. When the compiler begins compiling a rep or a
10
- # layout, it will be placed on the stack; when it is done compiling the
11
- # rep or layout, it will be removed from the stack.
12
- attr_reader :stack
13
-
14
- # The list of compilation rules that will be used to compile items. This
15
- # array will be filled by Nanoc3::Site#load_data.
16
- attr_reader :item_compilation_rules
17
-
18
- # The list of routing rules that will be used to give all items a path.
19
- # This array will be filled by Nanoc3::Site#load_data.
20
- attr_reader :item_routing_rules
21
-
22
- # The hash containing layout-to-filter mapping rules.
23
- attr_reader :layout_filter_mapping
24
-
25
- # Creates a new compiler for the given site.
26
- def initialize(site)
27
- @site = site
28
-
29
- @stack = []
30
-
31
- @item_compilation_rules = []
32
- @item_routing_rules = []
33
- @layout_filter_mapping = {}
34
- end
35
-
36
- # Compiles (part of) the site and writes out the compiled item
37
- # representations.
38
- #
39
- # +items+:: The items that should be compiled, along with their
40
- # dependencies. Pass +nil+ if the entire site should be
41
- # compiled.
42
- #
43
- # This method also accepts a few optional parameters:
44
- #
45
- # +:force+:: true if the rep should be compiled even if it is not
46
- # outdated, false if not. Defaults to false.
47
- def run(item=nil, params={})
48
- # Create output directory if necessary
49
- FileUtils.mkdir_p(@site.config[:output_dir])
50
-
51
- # Load dependencies
52
- dependency_tracker.load_graph
53
- print_dependency_graph if $DEBUG
54
-
55
- # Get items and reps to compile
56
- if item
57
- items = [ item ] + dependency_tracker.all_inverse_dependencies_for(item)
58
- items.uniq!
59
- else
60
- items = @site.items
61
- end
62
- reps = items.map { |i| i.reps }.flatten
63
-
64
- # Prepare dependencies
65
- remember_old_dependencies
66
- @old_dep_graph = dependency_tracker.instance_eval { @graph }.dup
67
- mark_outdated_items(reps, params.has_key?(:force) && params[:force])
68
- forget_dependencies_if_outdated(items)
69
-
70
- # Compile reps
71
- dependency_tracker.start
72
- compile_reps(reps)
73
- dependency_tracker.stop
74
-
75
- # Store dependencies
76
- dependency_tracker.store_graph
77
- end
78
-
79
- # Returns the first matching compilation rule for the given rep.
80
- def compilation_rule_for(rep)
81
- @item_compilation_rules.find do |rule|
82
- rule.applicable_to?(rep.item) && rule.rep_name == rep.name
83
- end
84
- end
85
-
86
- # Returns the first matching routing rule for the given rep.
87
- def routing_rule_for(rep)
88
- @item_routing_rules.find do |rule|
89
- rule.applicable_to?(rep.item) && rule.rep_name == rep.name
90
- end
91
- end
92
-
93
- # Returns a tuple containing the filter name and the filter arguments for
94
- # the given layout.
95
- def filter_for_layout(layout)
96
- @layout_filter_mapping.each_pair do |layout_identifier, filter_name_and_args|
97
- return filter_name_and_args if layout.identifier =~ layout_identifier
98
- end
99
- nil
100
- end
101
-
102
- private
103
-
104
- # Compiles all item representations in the site.
105
- def compile_reps(reps)
106
- active_reps, skipped_reps = reps.partition { |rep| rep.outdated? || rep.item.dependencies_outdated? }
107
- inactive_reps = []
108
- compiled_reps = []
109
-
110
- # Repeat as long as something is successfully compiled...
111
- changed = true
112
- until !changed
113
- changed = false
114
-
115
- # Sort by increasing number of inverse dependencies to speed up compilation
116
- #active_reps = active_reps.sort_by { |r| dependency_tracker.all_dependencies_for(r.item).size }
117
- # 10.times { puts '=' * 80 }
118
- # active_reps.each do |r|
119
- # puts r.item.identifier + ' => ' + dependency_tracker.all_dependencies_for(r.item).size.to_s
120
- # end
121
- # 10.times { puts '=' * 80 }
122
-
123
- # Attempt to compile all active reps
124
- until active_reps.empty?
125
- @stack.clear
126
- begin
127
- rep = active_reps.shift
128
- puts "*** Attempting to compile #{rep.inspect}" if $DEBUG
129
-
130
- @stack.push(rep)
131
- compile_rep(rep)
132
- rescue Nanoc3::Errors::UnmetDependency => e
133
- puts "*** Attempt failed due to unmet dependency on #{e.rep.inspect}" if $DEBUG
134
-
135
- # Save rep to compile it later
136
- inactive_reps << rep
137
-
138
- # Add dependency to list of items to compile
139
- unless active_reps.include?(e.rep) || inactive_reps.include?(e.rep)
140
- changed = true
141
- skipped_reps.delete(e.rep)
142
- inactive_reps.unshift(e.rep)
143
- end
144
-
145
- # Assume that this page has more dependencies and add those
146
- @old_dependencies[rep.item].each do |i|
147
- i.reps.each do |r|
148
- next if active_reps.include?(r)
149
- next if compiled_reps.include?(r)
150
- next if inactive_reps.include?(r)
151
-
152
- inactive_reps.unshift(r)
153
- end
154
- end
155
- else
156
- puts "*** Attempt succeeded" if $DEBUG
157
-
158
- changed = true
159
- compiled_reps << rep
160
- end
161
- puts if $DEBUG
162
- end
163
-
164
- # Retry
165
- puts "*** No active reps left; activating all (#{inactive_reps.size}) inactive reps" if $DEBUG
166
- puts if $DEBUG
167
- active_reps = inactive_reps
168
- inactive_reps = []
169
- end
170
-
171
- # Notify skipped reps
172
- skipped_reps.each do |rep|
173
- Nanoc3::NotificationCenter.post(:compilation_started, rep)
174
- Nanoc3::NotificationCenter.post(:compilation_ended, rep)
175
- end
176
-
177
- # Raise error if some active but non-compileable reps are left
178
- if !active_reps.empty?
179
- raise Nanoc3::Errors::RecursiveCompilation.new(active_reps)
180
- end
181
- end
182
-
183
- # Compiles the given item representation.
184
- #
185
- # This method should not be called directly; please use
186
- # Nanoc3::Compiler#run instead, and pass this item representation's item as
187
- # its first argument.
188
- #
189
- # +rep+:: The rep that is to be compiled.
190
- def compile_rep(rep)
191
- # Start
192
- Nanoc3::NotificationCenter.post(:compilation_started, rep)
193
- Nanoc3::NotificationCenter.post(:visit_started, rep.item)
194
-
195
- # Apply matching rule
196
- compilation_rule_for(rep).apply_to(rep)
197
- rep.compiled = true
198
-
199
- # Write if rep is routed
200
- rep.write unless rep.raw_path.nil?
201
-
202
- # Stop
203
- Nanoc3::NotificationCenter.post(:visit_ended, rep.item)
204
- Nanoc3::NotificationCenter.post(:compilation_ended, rep)
205
- end
206
-
207
- # Returns the dependency tracker for this site.
208
- def dependency_tracker
209
- @dependency_tracker ||= Nanoc3::DependencyTracker.new(@site.items)
210
- end
211
-
212
- # Marks the necessary items as outdated.
213
- def mark_outdated_items(reps, force)
214
- if force
215
- reps.each { |r| r.force_outdated = true }
216
- else
217
- dependency_tracker.mark_outdated_items
218
- end
219
- end
220
-
221
- # Clears the list of dependencies for items that will be recompiled.
222
- def forget_dependencies_if_outdated(items)
223
- items.each do |i|
224
- if i.outdated? || i.dependencies_outdated?
225
- dependency_tracker.forget_dependencies_for(i)
226
- end
227
- end
228
- end
229
-
230
- def remember_old_dependencies
231
- @old_dependencies = dependency_tracker.instance_eval { @graph }.dup
232
- end
233
-
234
- # Prints the dependency graph.
235
- def print_dependency_graph
236
- graph = dependency_tracker.instance_eval { @graph }
237
- puts "DEPENDENCY GRAPH:"
238
- graph.each_pair do |key, values|
239
- puts "#{key.inspect} depends on:"
240
- values.each do |value|
241
- puts " #{value.inspect}"
242
- end
243
- puts " (nothing!)" if values.empty?
244
- puts
245
- end
246
- end
247
-
248
- end
249
-
250
- end
@@ -1,104 +0,0 @@
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