awestructx 0.4.0 → 0.4.1.x1

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.
Files changed (37) hide show
  1. data/lib/awestruct/astruct_mixin.rb +13 -3
  2. data/lib/awestruct/cli/auto.rb +18 -4
  3. data/lib/awestruct/cli/deploy.rb +38 -0
  4. data/lib/awestruct/cli/invoker.rb +12 -1
  5. data/lib/awestruct/config.rb +10 -0
  6. data/lib/awestruct/dependencies.rb +102 -0
  7. data/lib/awestruct/deploy/github_pages_deploy.rb +61 -0
  8. data/lib/awestruct/deploy/rsync_deploy.rb +51 -0
  9. data/lib/awestruct/deployers.rb +15 -0
  10. data/lib/awestruct/engine.rb +49 -13
  11. data/lib/awestruct/extensions/atomizer.rb +3 -3
  12. data/lib/awestruct/extensions/minify.rb +21 -23
  13. data/lib/awestruct/extensions/posts.rb +4 -4
  14. data/lib/awestruct/extensions/sitemap.rb +1 -0
  15. data/lib/awestruct/handler_chains.rb +15 -32
  16. data/lib/awestruct/handlers/asciidoc_handler.rb +57 -0
  17. data/lib/awestruct/handlers/base_handler.rb +23 -4
  18. data/lib/awestruct/handlers/coffeescript_handler.rb +48 -0
  19. data/lib/awestruct/handlers/erb_handler.rb +44 -0
  20. data/lib/awestruct/handlers/file_handler.rb +6 -3
  21. data/lib/awestruct/handlers/front_matter_handler.rb +5 -0
  22. data/lib/awestruct/handlers/haml_handler.rb +14 -2
  23. data/lib/awestruct/handlers/layout_handler.rb +4 -2
  24. data/lib/awestruct/handlers/markdown_handler.rb +14 -0
  25. data/lib/awestruct/handlers/orgmode_handler.rb +48 -0
  26. data/lib/awestruct/handlers/page_delegating_handler.rb +54 -0
  27. data/lib/awestruct/handlers/restructuredtext_handler.rb +67 -0
  28. data/lib/awestruct/handlers/sass_handler.rb +7 -0
  29. data/lib/awestruct/handlers/scss_handler.rb +7 -0
  30. data/lib/awestruct/handlers/textile_handler.rb +15 -0
  31. data/lib/awestruct/layouts.rb +1 -0
  32. data/lib/awestruct/page.rb +27 -14
  33. data/lib/awestruct/page_loader.rb +15 -5
  34. data/lib/awestruct/pipeline.rb +7 -0
  35. data/lib/awestruct/version.rb +1 -1
  36. data/lib/guard/awestruct.rb +1 -1
  37. metadata +173 -267
@@ -1,4 +1,6 @@
1
1
 
2
+ require 'awestruct/dependencies'
3
+
2
4
  module Awestruct
3
5
 
4
6
  module AStructMixin
@@ -21,7 +23,7 @@ module Awestruct
21
23
 
22
24
  def [](key)
23
25
  r = super( key ) || super( key.to_sym ) || super( key.to_s )
24
- transform_entry( r )
26
+ transform_entry( key, r )
25
27
  end
26
28
 
27
29
  def method_missing(sym, *args, &blk)
@@ -46,8 +48,11 @@ module Awestruct
46
48
  end
47
49
  end
48
50
 
51
+ UNTRACKED_KEYS = [
52
+ :url,
53
+ ]
49
54
 
50
- def transform_entry(entry)
55
+ def transform_entry(for_key, entry)
51
56
  r = case(entry)
52
57
  when AStructMixin
53
58
  entry
@@ -55,10 +60,15 @@ module Awestruct
55
60
  #AStruct.new( entry )
56
61
  entry.extend( AStructMixin )
57
62
  when Array
58
- entry.map!{|i| transform_entry(i)}
63
+ entry.map!{|i| transform_entry( for_key, i)}
59
64
  else
60
65
  entry
61
66
  end
67
+ if ( self.is_a? Awestruct::Page )
68
+ unless UNTRACKED_KEYS.include? for_key.to_sym
69
+ Awestruct::Dependencies.track_dependency( self )
70
+ end
71
+ end
62
72
  r
63
73
  end
64
74
 
@@ -4,17 +4,31 @@ module Awestruct
4
4
  module CLI
5
5
  class Auto
6
6
 
7
- def initialize(path)
8
- @path = path
7
+ def initialize(config)
8
+ @config = config
9
9
  end
10
10
 
11
11
  def run()
12
12
  Guard.setup
13
- Guard.start( :guardfile=>File.dirname(__FILE__) + '/Guardfile',
14
- :watchdir=>@path,
13
+ Guard.start( :guardfile_contents=>guardfile_contents,
14
+ :watchdir=>@config.dir,
15
15
  :watch_all_modifications=>true )
16
16
  end
17
17
 
18
+ def guardfile_contents
19
+ ignored = [
20
+ "'.awestruct'",
21
+ "'#{File.basename( @config.tmp_dir )}'",
22
+ "'#{File.basename( @config.output_dir )}'",
23
+ ]
24
+ c = ''
25
+ c += "guard :awestruct do\n"
26
+ c += " watch %r(.*)\n"
27
+ c += " ignore_paths #{ignored.join(', ')}"
28
+ c += "end\n"
29
+ c
30
+ end
18
31
  end
32
+
19
33
  end
20
34
  end
@@ -0,0 +1,38 @@
1
+ require 'awestruct/deploy/rsync_deploy'
2
+ require 'awestruct/deploy/github_pages_deploy'
3
+
4
+ module Awestruct
5
+ module CLI
6
+
7
+ class Deploy
8
+
9
+ attr_accessor :site_config
10
+ attr_accessor :deploy_config
11
+
12
+ def initialize(site_config, deploy_config)
13
+ @site_config = site_config
14
+ @deploy_config = deploy_config
15
+ end
16
+
17
+ def run()
18
+ deploy_type = :rsync
19
+
20
+ if ( deploy_config['host'] == 'github_pages' )
21
+ deploy_type = :github_pages
22
+ end
23
+
24
+ deployer_class = Awestruct::Deployers.instance[ deploy_type ]
25
+
26
+ if ( deployer_class.nil? )
27
+ $stderr.puts "Unable to locate correct deployer for #{deploy_type}"
28
+ return
29
+ end
30
+
31
+ deployer = deployer_class.new( site_config, deploy_config )
32
+ deployer.run
33
+
34
+ end
35
+ end
36
+
37
+ end
38
+ end
@@ -3,6 +3,7 @@ require 'awestruct/cli/options'
3
3
  require 'awestruct/cli/generate'
4
4
  require 'awestruct/cli/auto'
5
5
  require 'awestruct/cli/server'
6
+ require 'awestruct/cli/deploy'
6
7
 
7
8
  require 'pathname'
8
9
 
@@ -64,6 +65,7 @@ module Awestruct
64
65
 
65
66
  def setup_config()
66
67
  @config = Awestruct::Config.new( Dir.pwd )
68
+ @config.track_dependencies = true if ( options.auto )
67
69
  end
68
70
 
69
71
  def invoke_init()
@@ -73,6 +75,7 @@ module Awestruct
73
75
  end
74
76
 
75
77
  def invoke_force()
78
+ FileUtils.rm_rf( File.join( config.dir, '.awestruct', 'dependency-cache' ) )
76
79
  FileUtils.rm_rf( config.output_dir )
77
80
  end
78
81
 
@@ -81,10 +84,18 @@ module Awestruct
81
84
  end
82
85
 
83
86
  def invoke_deploy()
87
+ deploy_config = profile[ 'deploy' ]
88
+
89
+ if ( deploy_config.nil? )
90
+ $stderr.puts "No configuration for 'deploy'"
91
+ return
92
+ end
93
+
94
+ Awestruct::CLI::Deploy.new( config, deploy_config ).run
84
95
  end
85
96
 
86
97
  def invoke_auto()
87
- run_in_thread( Awestruct::CLI::Auto.new( config.dir ) )
98
+ run_in_thread( Awestruct::CLI::Auto.new( config ) )
88
99
  end
89
100
 
90
101
  def invoke_server()
@@ -12,6 +12,10 @@ module Awestruct
12
12
  attr_accessor :skin_dir
13
13
  attr_accessor :tmp_dir
14
14
  attr_accessor :ignore
15
+ attr_accessor :track_dependencies
16
+
17
+ attr_accessor :images_dir
18
+ attr_accessor :stylesheets_dir
15
19
 
16
20
  def initialize(dir = Dir.pwd)
17
21
  @dir = Pathname.new( dir )
@@ -22,7 +26,13 @@ module Awestruct
22
26
  @extension_dir = Pathname.new( File.join(dir, '_ext') )
23
27
  @skin_dir = Pathname.new( File.join(dir, '_skin') )
24
28
  @tmp_dir = Pathname.new( File.join(dir, '_tmp') )
29
+
30
+ @images_dir = Pathname.new( File.join(dir, 'images') )
31
+ @stylesheets_dir = Pathname.new( File.join(dir, 'stylesheets') )
32
+
25
33
  @ignore = File.exists?(ignore_file = File.join(dir, ".awestruct_ignore")) ? Dir[*IO.read(ignore_file).each_line.map(&:strip)] : []
34
+
35
+ @track_dependencies = false
26
36
  end
27
37
 
28
38
  end
@@ -0,0 +1,102 @@
1
+
2
+ module Awestruct
3
+ class Dependencies
4
+
5
+ attr_reader :page
6
+ attr_reader :dependencies
7
+ attr_reader :dependents
8
+
9
+
10
+ def self.top_page
11
+ @pages ||= []
12
+ @pages.first
13
+ end
14
+
15
+ def self.push_page(page)
16
+ if ( top_page.nil? )
17
+ page.dependencies.clear
18
+ else
19
+ top_page.dependencies.add_dependency( page )
20
+ end
21
+ @pages.push( page )
22
+ end
23
+
24
+ def self.pop_page
25
+ page = @pages.pop
26
+ if ( @pages.empty? && ! page.nil? )
27
+ page.dependencies.persist!
28
+ end
29
+ end
30
+
31
+
32
+ def self.track_dependency(dep)
33
+ return if top_page.nil?
34
+ return if top_page == dep
35
+ top_page.dependencies.add_dependency(dep)
36
+ end
37
+
38
+ def initialize(page)
39
+ @page = page
40
+ @dependencies = Set.new
41
+ @dependents = Set.new
42
+ end
43
+
44
+ def <<(dep)
45
+ add_dependency( dep )
46
+ end
47
+
48
+ def add_dependency(dep)
49
+ return if @page.do_not_track_dependencies
50
+ return if @page.output_path.nil?
51
+ return if dep == @page
52
+ @dependencies << dep
53
+ dep.dependencies.add_dependent( page )
54
+ end
55
+
56
+ def add_dependent(dep)
57
+ @dependents << dep
58
+ end
59
+
60
+ def remove_dependent(dep)
61
+ @dependents.delete( dep )
62
+ end
63
+
64
+ def clear
65
+ @dependencies.clear
66
+ @dependents.each{|d| d.remove_dependent( page ) }
67
+ end
68
+
69
+ def persist!
70
+ return if page.output_path.nil? || page.output_path == ''
71
+ file = File.join( @page.site.config.dir, '.awestruct', 'dependency-cache', page.output_path )
72
+ FileUtils.mkdir_p( File.dirname( file ) )
73
+ File.open( file, 'w' ) do |file|
74
+ @dependencies.collect{|e| e.relative_source_path }.uniq.each do |d|
75
+ file.puts d unless d.nil?
76
+ end
77
+ end
78
+ end
79
+
80
+ def load!
81
+ return if page.output_path.nil? || page.output_path == ''
82
+ file = File.join( @page.site.config.dir, '.awestruct', 'dependency-cache', page.output_path )
83
+ #puts "load #{file}"
84
+ if ( File.exist?( file ) )
85
+ File.open( file, 'r' ) do |file|
86
+ file.lines.each do |line|
87
+ d = find_page_by_path( line.strip )
88
+ add_dependency( d ) unless d.nil?
89
+ end
90
+ end
91
+ return true
92
+ end
93
+ false
94
+ end
95
+
96
+ def find_page_by_path(path)
97
+ page.site.pages_by_relative_source_path[ path ]
98
+ end
99
+
100
+
101
+ end
102
+ end
@@ -0,0 +1,61 @@
1
+ require 'awestruct/deployers'
2
+
3
+ module Awestruct
4
+ module Deploy
5
+
6
+ class GitHubPagesDeploy
7
+ def initialize( site_config, deploy_config )
8
+ @site_path = site_config.output_dir
9
+ @branch = deploy_config[ 'branch' ] || 'gh-pages'
10
+ end
11
+
12
+ def run
13
+ git.status.changed.empty? ? publish_site : message_for(:existing_changes)
14
+ end
15
+
16
+ private
17
+ def git
18
+ @git ||= Git.open('.')
19
+ end
20
+
21
+ def publish_site
22
+ current_branch = git.branch
23
+ checkout_pages_branch
24
+ add_and_commit_site @site_path
25
+ push_and_restore current_branch
26
+ end
27
+
28
+ def checkout_pages_branch
29
+ git.branch( @branch ).checkout
30
+ end
31
+
32
+ def add_and_commit_site( path )
33
+ git.with_working( path ) do
34
+ git.add(".")
35
+ begin
36
+ git.commit("Published #{@branch} to GitHub pages.")
37
+ rescue Git::GitExecuteError => e
38
+ $stderr.puts "Can't commit. #{e}."
39
+ end
40
+ end
41
+ end
42
+
43
+ def push_and_restore( original_branch )
44
+ git.reset_hard
45
+ git.push( 'origin', @branch )
46
+ git.checkout( original_branch )
47
+ end
48
+
49
+ def message_for( key )
50
+ $stderr.puts case key
51
+ when :existing_changes
52
+ "You have uncommitted changes in the working branch. Please commit or stash them."
53
+ else
54
+ "An error occured."
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ Awestruct::Deployers.instance[ :github_pages ] = Awestruct::Deploy::GitHubPagesDeploy
@@ -0,0 +1,51 @@
1
+ require 'awestruct/deployers'
2
+
3
+ require 'open3'
4
+
5
+ module Awestruct
6
+ module Deploy
7
+ class RSyncDeploy
8
+
9
+ def initialize(site_config, deploy_config)
10
+ @site_path = File.join( site_config.output_dir, '/' )
11
+ @host = deploy_config['host']
12
+ @path = File.join( deploy_config['path'], '/' )
13
+ end
14
+
15
+ def run
16
+ cmd = "rsync -r -l -i --no-p --no-g --chmod=Dg+s,ug+w --delete #{@site_path} #{@host}:#{@path}"
17
+ Open3.popen3( cmd ) do |stdin, stdout, stderr|
18
+ stdin.close
19
+ threads = []
20
+ threads << Thread.new(stdout) do |i|
21
+ while ( ! i.eof? )
22
+ line = i.readline
23
+ case line[0,9]
24
+ when '<f.sT....'
25
+ puts " updating #{line[10..-1]}"
26
+ when 'cd+++++++'
27
+ puts " creating #{line[10..-1]}"
28
+ when '<f+++++++'
29
+ puts " adding #{line[10..-1]}"
30
+ when '<f..T....'
31
+ # ignoring unchanged files
32
+ # puts " no change to #{line[10..-1]}"
33
+ else
34
+ puts line
35
+ end
36
+ end
37
+ end
38
+ threads << Thread.new(stderr) do |i|
39
+ while ( ! i.eof? )
40
+ line = i.readline
41
+ puts line
42
+ end
43
+ end
44
+ threads.each{|t|t.join}
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ Awestruct::Deployers.instance[ :rsync ] = Awestruct::Deploy::RSyncDeploy
@@ -0,0 +1,15 @@
1
+
2
+ module Awestruct
3
+
4
+ class Deployers < Hash
5
+ def self.instance
6
+ @instance ||= Deployers.new
7
+ end
8
+
9
+ def self.register( key, cls )
10
+ Deployers.instance[ key.to_sym ] = cls
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -10,6 +10,7 @@ require 'awestruct/page_loader'
10
10
  require 'awestruct/extensions/pipeline'
11
11
 
12
12
  require 'fileutils'
13
+ require 'set'
13
14
 
14
15
  class OpenStruct
15
16
  def inspect
@@ -38,7 +39,6 @@ module Awestruct
38
39
  @pipeline = Pipeline.new
39
40
  @site_page_loader = PageLoader.new( @site )
40
41
  @layout_page_loader = PageLoader.new( @site, :layouts )
41
- adjust_load_path
42
42
  end
43
43
 
44
44
  def config
@@ -46,6 +46,7 @@ module Awestruct
46
46
  end
47
47
 
48
48
  def run(profile, base_url, default_base_url, force=false)
49
+ adjust_load_path
49
50
  load_site_yaml(profile)
50
51
  set_base_url( base_url, default_base_url )
51
52
  load_yamls
@@ -54,9 +55,24 @@ module Awestruct
54
55
  execute_pipeline
55
56
  configure_compass
56
57
  set_urls( site.pages )
58
+ build_page_index
57
59
  generate_output
58
60
  end
59
61
 
62
+ def build_page_index
63
+ site.pages_by_relative_source_path = {}
64
+ site.pages.each do |p|
65
+ if ( p.relative_source_path )
66
+ site.pages_by_relative_source_path[ p.relative_source_path ] = p
67
+ end
68
+ end
69
+ site.layouts.each do |p|
70
+ if ( p.relative_source_path )
71
+ site.pages_by_relative_source_path[ p.relative_source_path ] = p
72
+ end
73
+ end
74
+ end
75
+
60
76
  def set_base_url(base_url, default_base_url)
61
77
  if ( base_url )
62
78
  site.base_url = base_url
@@ -191,27 +207,47 @@ module Awestruct
191
207
  generated_path = File.join( site.config.output_dir, page.output_path )
192
208
  if ( page.stale_output?( generated_path ) )
193
209
  generate_page( page, generated_path )
210
+ else
211
+ generate_page( page, generated_path, false )
194
212
  end
195
213
  end
196
214
  end
197
215
 
198
- def generate_page(page, generated_path)
199
- puts "Generating: #{generated_path}"
200
- FileUtils.mkdir_p( File.dirname( generated_path ) )
201
- File.open( generated_path, 'w' ) do |file|
202
- file << page.rendered_content
216
+ def generate_page(page, generated_path, produce_output=true)
217
+ if ( produce_output )
218
+ puts "Generating: #{generated_path}"
219
+ FileUtils.mkdir_p( File.dirname( generated_path ) )
220
+ File.open( generated_path, 'w' ) do |file|
221
+ file << page.rendered_content
222
+ end
223
+ elsif ( site.config.track_dependencies )
224
+ if page.dependencies.load!
225
+ puts "Cached: #{generated_path}"
226
+ else
227
+ puts "Analyzing: #{generated_path}"
228
+ page.rendered_content
229
+ end
203
230
  end
204
231
  end
205
232
 
206
233
  def generate_page_by_output_path(path)
207
234
  full_path = File.join( '', path )
208
- #puts "regen path #{full_path}"
209
- page = site.pages.find{|p| p.relative_source_path.to_s==full_path}
210
- if ( page.nil? )
211
- #puts "Unable to locate page for #{path}"
212
- else
213
- generated_path = File.join( site.config.output_dir, page.output_path )
214
- generate_page(page, generated_path)
235
+ page = site.pages.find{|p| p.relative_source_path.to_s==full_path} || site.layouts.find{|p| p.relative_source_path.to_s==full_path}
236
+ return if page.nil?
237
+
238
+ #puts "regen page #{page.inspect}"
239
+ #puts "page.dependents #{page.dependencies.dependents.inspect}"
240
+
241
+ regen_pages = Set.new
242
+ regen_pages << page unless ( page.output_path.nil? )
243
+ regen_pages += page.dependencies.dependents
244
+
245
+ #puts regen_pages.collect{|e|e.output_path}.inspect
246
+ regen_pages.each do |p|
247
+ unless ( p.output_path.nil? || p.__is_layout )
248
+ generated_path = File.join( site.config.output_dir, p.output_path )
249
+ generate_page( p, generated_path )
250
+ end
215
251
  end
216
252
  end
217
253
 
@@ -2,8 +2,8 @@ module Awestruct
2
2
  module Extensions
3
3
  class Atomizer
4
4
 
5
- def initialize(entries_name, output_path, opts={})
6
- @entries_name = entries_name
5
+ def initialize(entries, output_path, opts={})
6
+ @entries = entries
7
7
  @output_path = output_path
8
8
  @num_entries = opts[:num_entries] || 50
9
9
  @content_url = opts[:content_url]
@@ -11,7 +11,7 @@ module Awestruct
11
11
  end
12
12
 
13
13
  def execute(site)
14
- entries = site.send( @entries_name ) || []
14
+ entries = @entries.is_a?(Array) ? @entries : site.send( @entries ) || []
15
15
  unless ( @num_entries == :all )
16
16
  entries = entries[0, @num_entries]
17
17
  end
@@ -12,10 +12,10 @@ require 'fileutils'
12
12
  #
13
13
  # These commands must be available on your PATH in order to use them.
14
14
  #
15
- # This class is loaded as a transformer in the Awestruct pipeline. The
15
+ # This class is loaded as a transformer into the Awestruct pipeline. The
16
16
  # constructor accepts an array of symbols representing the file types to minimize.
17
17
  #
18
- # extension Awestruct::Extensions::Minify.new
18
+ # transformer Awestruct::Extensions::Minify.new
19
19
  #
20
20
  # This transform recognizes the following symbols:
21
21
  #
@@ -57,30 +57,28 @@ module Awestruct
57
57
 
58
58
  def transform(site, page, input)
59
59
  if site.minify
60
- ext = File.extname(page.output_path)[1..-1].to_sym
61
- if @types.include?(ext)
62
- case ext
63
- when :html
64
- print "minifying html #{page.output_path}"
65
- htmlcompressor(page, input, site.minify_html_opts)
66
- when :css
67
- print "minifying css #{page.output_path}"
68
- yuicompressor(page, input, :css)
69
- when :js
70
- print "minifying js #{page.output_path}"
71
- yuicompressor(page, input, :js)
72
- when :png
73
- print "minifying png #{page.output_path}"
74
- pngcrush(page, input)
75
- else
76
- input
60
+ ext = File.extname(page.output_path)
61
+ if !ext.empty?
62
+ ext_sym = ext[1..-1].to_sym
63
+ if @types.include?(ext_sym)
64
+ case ext_sym
65
+ when :html
66
+ print "minifying html #{page.output_path}"
67
+ input = htmlcompressor(page, input, site.minify_html_opts)
68
+ when :css
69
+ print "minifying css #{page.output_path}"
70
+ input = yuicompressor(page, input, :css)
71
+ when :js
72
+ print "minifying js #{page.output_path}"
73
+ input = yuicompressor(page, input, :js)
74
+ when :png
75
+ print "minifying png #{page.output_path}"
76
+ input = pngcrush(page, input)
77
+ end
77
78
  end
78
- else
79
- input
80
79
  end
81
- else
82
- input
83
80
  end
81
+ input
84
82
  end
85
83
 
86
84
  private
@@ -27,22 +27,22 @@ module Awestruct
27
27
  date = Time.parse page.date
28
28
  end
29
29
  year = date.year
30
- month = date.month
31
- day = date.day
30
+ month = sprintf( "%02d", date.month )
31
+ day = sprintf( "%02d", date.day )
32
32
  page.date = Time.utc(year, month, day)
33
33
  slug = $1
34
34
  end
35
35
 
36
36
  # if a date was found create a post
37
37
  if( year and month and day)
38
- page.slug = slug
38
+ page.slug ||= slug
39
39
  #context = OpenStruct.new({
40
40
  #:site=>site,
41
41
  #:page=>page,
42
42
  #})
43
43
  context = page.create_context
44
44
  #page.body = page.render( context )
45
- page.output_path = "#{@path_prefix}/#{year}/#{month}/#{day}/#{slug}.html"
45
+ page.output_path = "#{@path_prefix}/#{year}/#{month}/#{day}/#{page.slug}.html"
46
46
  #page.layout = 'post'
47
47
  posts << page
48
48
  end
@@ -33,6 +33,7 @@ module Awestruct
33
33
  page = site.engine.load_page( sitemap )
34
34
  page.output_path = 'sitemap.xml'
35
35
  page.sitemap_entries = sitemap_pages
36
+ page.do_not_track_dependencies = true
36
37
 
37
38
  # Add the sitemap to our site
38
39
  site.pages << page