sitemapper 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Carlos Júnior, Milk-it Software House
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,121 @@
1
+ = Sitemapper - Easy SEO engine
2
+
3
+ Sitemapper will help you in various SEO techniques such as sitemap.xml
4
+ auto generation.
5
+
6
+ == Installation
7
+
8
+ You can install the development version with
9
+
10
+ % sudo gem install milk-it-sitemapper -s http://gems.github.com
11
+
12
+ Or the release version with
13
+
14
+ % sudo gem install sitemapper
15
+
16
+
17
+ == Examples
18
+
19
+ === Ruby On Rails
20
+
21
+ Sitemapper will automagically generate a sitemap.xml file for you when
22
+ your rails application start, this sitemap.xml will include all your
23
+ URLs that Sitemapper consider 'static', for example:
24
+
25
+ map.todo '/to-do' # Sitemapper will consider this as static
26
+ map.articles '/articles/:year/:month' # Will be considered this dynamic
27
+ map.connect '*path' # Will be considered dynamic
28
+
29
+ The generation of your sitemap.xml will happen on your application boot,
30
+ but it won't delete any URL previous added (we hope to be able to do so
31
+ very soon - a merge).
32
+
33
+ In your application, you can use the accessors provided by Sitemapper to
34
+ dynamically add URLs, for example, supose a blog app:
35
+
36
+ class ArticlesController < ApplicationController
37
+ ...
38
+ def create
39
+ # do all the creation stuff
40
+ map_url(article_url(@article)) # add the URL to your sitemap
41
+ end
42
+
43
+ def destroy
44
+ # do all the deletion stuff
45
+ unmap_url(article_url(@article))
46
+ end
47
+ ...
48
+ end
49
+
50
+ You can also do it on your sweepers (which is a better choice)
51
+
52
+ class ArticleSweeper < ActionController::Caching::Sweeper
53
+ observe Article, Account
54
+
55
+ def after_create(record)
56
+ # expire everything you need
57
+ map_url(polymorphic_url(record))
58
+ end
59
+
60
+ def after_destroy(record)
61
+ # expire everything you need
62
+ map_url(polymorphic_url(record))
63
+ end
64
+ end
65
+
66
+ === Merb
67
+
68
+ Sorry, we do not support Merb yet. (Actually, it will depend on the
69
+ demand)
70
+
71
+ === Other SEO techniques
72
+
73
+ With SEO, you'll have some view helpers to easily apply some SEO
74
+ techniques to your website/webapp.
75
+
76
+ In your application layout, just do it:
77
+
78
+ <head>
79
+ <%= title('My Personal Blog') %>
80
+ <%= page_meta %>
81
+ </head>
82
+
83
+ And in your action views, you put this:
84
+
85
+ <% page(:title => 'Contact',
86
+ :desc => 'Here you'll can contact our customer support ...',
87
+ :keywords => 'contact, support, customer') %>
88
+
89
+ In this case, the view will be rendered in this way:
90
+
91
+ <head>
92
+ <title>Contact :: My Personal Blog</title>
93
+ <meta name="description" content="Here you'll can contact our customer support ..." />
94
+ <meta name="keywords" content="contact, support, customer" />
95
+ </head>
96
+
97
+ If you want to change the title separator, just do:
98
+
99
+ ...
100
+ <%= title('My Personal Blog', :separator => ' - ') %>
101
+ ...
102
+
103
+ Or, you can als use any object that respond to title or name (for
104
+ page title), short_description or description, tag_list or keywords.
105
+
106
+ <% page(@event) %>
107
+
108
+ If you want to suggest any other SEO technique, suggest it on
109
+ carlos@milk-it.net
110
+
111
+ === Hope you enjoy!
112
+
113
+ == To do:
114
+
115
+ * Add sitemap options to routes
116
+ * Create separate files for dynamic and static routes (then, we'll can
117
+ delete all the static on startup)
118
+ * Write test code (sorry, I really didn't it)
119
+
120
+ Copyright (c) 2008 Carlos Júnior, released under the MIT license
121
+ Copyright (c) 2008 Milk-it Software House, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,22 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the sitemaper plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.pattern = 'test/**/*_test.rb'
12
+ t.verbose = true
13
+ end
14
+
15
+ desc 'Generate documentation for the sitemaper plugin.'
16
+ Rake::RDocTask.new(:rdoc) do |rdoc|
17
+ rdoc.rdoc_dir = 'rdoc'
18
+ rdoc.title = 'Sitemaper'
19
+ rdoc.options << '--line-numbers' << '--inline-source'
20
+ rdoc.rdoc_files.include('README')
21
+ rdoc.rdoc_files.include('lib/**/*.rb')
22
+ end
data/init.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'sitemapper'
2
+
3
+ if Object.const_defined?('Rails')
4
+ require 'sitemapper/adapters/rails_adapter'
5
+ Sitemapper::Adapters::RailsAdapter.install!
6
+ end
data/install.rb ADDED
@@ -0,0 +1,2 @@
1
+ puts "ATTENTION!!!"
2
+ puts "You have to setup config.action_controller.relative_url_root\non your config to Sitemapper work correctly!"
data/lib/sitemapper.rb ADDED
@@ -0,0 +1,20 @@
1
+ require 'sitemapper/helpers'
2
+ require 'sitemapper/map'
3
+ require 'sitemapper/accessors'
4
+
5
+ module Sitemapper
6
+ MAJOR, MINOR, TINY = 0, 2, 0 #:nodoc:
7
+
8
+ # Get the running version of Sitemapper
9
+ def version
10
+ [MAJOR, MINOR, TINY].join('.')
11
+ end
12
+
13
+ def self.map=(map)
14
+ @map = map
15
+ end
16
+
17
+ def self.map
18
+ @map or raise 'Uninitialized Sitemapper.map'
19
+ end
20
+ end
@@ -0,0 +1,54 @@
1
+ module Sitemapper
2
+ module Adapters
3
+ module RailsAdapter
4
+ module RoutesMapperExtension
5
+ include Sitemapper::Accessors
6
+
7
+ def self.included(base)
8
+ base.class_eval do
9
+ alias_method_chain :named_route, :sitemap
10
+ alias_method_chain :connect, :sitemap
11
+ alias_method_chain :root, :sitemap
12
+ end
13
+ end
14
+
15
+ def named_route_with_sitemap(name, path, options = {})
16
+ map_if_possible(path, options)
17
+ named_route_without_sitemap(name, path, options)
18
+ end
19
+
20
+ def connect_with_sitemap(path, options = {})
21
+ map_if_possible(path, options)
22
+ connect_without_sitemap(path, options)
23
+ end
24
+
25
+ def root_with_sitemap(options = {})
26
+ map_if_possible('/', options)
27
+ root_without_sitemap(options)
28
+ end
29
+
30
+ private
31
+
32
+ def map_if_possible(path, options)
33
+ # Don't map dynamic URLs
34
+ method = options[:conditions][:method] rescue :get
35
+ # TODO: extract options to map
36
+ unless path =~ /[:*]/ || method != :get
37
+ map_path(path)
38
+ end
39
+ end
40
+ end
41
+
42
+ # Install routing hooks, view helpers and initialize the
43
+ # sitemap.xml file
44
+ def self.install!
45
+ Sitemapper::Map.site_root = ActionController::Base.relative_url_root rescue
46
+ ActionController::AbstractRequest.relative_url_root
47
+ Sitemapper::map = Sitemapper::Map.new(File.join(Rails.root, 'public', 'sitemap.xml'))
48
+ ActionController::Routing::RouteSet::Mapper.send :include, RoutesMapperExtension
49
+ ActionView::Base.send :include, Sitemapper::Helpers
50
+ ActionController::Base.send :include, Sitemapper::Accessors
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,91 @@
1
+ module Sitemapper
2
+ module Helpers
3
+ # Set the page data for title and meta tags
4
+ #
5
+ # ==== Parameters
6
+ # * <tt>:title</tt> the title of the page
7
+ # * <tt>:desc</tt> the description of the current page
8
+ # * <tt>:keywords</tt> the keywords that represent the current page
9
+ #
10
+ # ==== The parameter can also be an object that respond to (used preferentially on this order):
11
+ # * <tt>title</tt> OR <tt>name</tt> (for title)
12
+ # * <tt>short_description</tt> OR <tt>description</tt> (for description)
13
+ # * <tt>tag_list</tt> OR <tt>keywords</tt> (for keywords)
14
+ #
15
+ # See <tt>page_meta</tt> for further information and examples.
16
+ #
17
+ def page(defs)
18
+ @_title = defs.delete(:title)
19
+ @_desc = defs.delete(:desc)
20
+ @_keys = defs.delete(:keywords)
21
+ end
22
+
23
+ def page_with_object(defs) # :nodoc:
24
+ return page_without_object(defs) if defs.is_a?(Hash)
25
+ @_title = if defs.respond_to?(:title)
26
+ defs.title
27
+ elsif defs.respond_to?(:name)
28
+ defs.name
29
+ end
30
+ @_desc = if defs.respond_to?(:short_description)
31
+ defs.short_description
32
+ elsif defs.respond_to?(:description)
33
+ defs.description
34
+ end
35
+ @_keys = if defs.respond_to?(:tag_list)
36
+ defs.tag_list
37
+ elsif defs.respond_to?(:keywords)
38
+ defs.keywords
39
+ end
40
+ end
41
+ alias_method_chain :page, :object
42
+
43
+ # Returns the title of the page with the website title
44
+ #
45
+ # ==== Parameters
46
+ #
47
+ # * the first parameter is the website title
48
+ # * the second parameter is a options hash:
49
+ # * <tt>:separator</tt> is the separator of the page and the website title
50
+ #
51
+ # See <tt>page_meta</tt> for further information and examples.
52
+ #
53
+ def title(title, opts={})
54
+ separator = opts[:separator] || ' :: '
55
+ content_tag(:title, @_title.nil?? title : "#{@_title}#{separator}#{title}")
56
+ end
57
+
58
+ # Returns the meta tags for the current page, for example:
59
+ #
60
+ # app/views/foo/bar.html.erb
61
+ #
62
+ # page(:title => 'Foo bar!',
63
+ # :description => 'Lorem ipsum dollar sit amet',
64
+ # :keywords => 'lorem, ipsum dollar, sit, amet')
65
+ #
66
+ # app/views/layouts/application.html.erb
67
+ #
68
+ # ...
69
+ # <head>
70
+ # <%= title('My Webste') %>
71
+ # <%= page_meta %>
72
+ # </head>
73
+ # ...
74
+ #
75
+ # The example above will output the following on the rendered page:
76
+ #
77
+ # ...
78
+ # <head>
79
+ # <title>Foo bar! :: My Website</title>
80
+ # <meta name="description" content="Lorem ipsum dollar sit amet" />
81
+ # <meta name="keywords" content="lore, ipsum dollar, sit, amet" />
82
+ # </head>
83
+ #
84
+ def page_meta
85
+ res = ''
86
+ res << tag(:meta, :name => 'description', :content => @_desc) if @_desc
87
+ res << tag(:meta, :name => 'keywords', :content => @_keys) if @_desc
88
+ return res
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,122 @@
1
+ require 'rexml/document'
2
+ require 'thread'
3
+ require 'uri'
4
+
5
+ module Sitemapper
6
+ class Map
7
+ SCHEMA = 'http://www.sitemaps.org/schemas/sitemap/0.9' #:nodoc:
8
+ INDENT = -1 #:nodoc:
9
+
10
+ # Returns the site root (previously defined with site_root=)
11
+ def self.site_root
12
+ @@site_root || 'http://www.example.com/'
13
+ end
14
+
15
+ # Set the site root for the generated URLs
16
+ #
17
+ # * <tt>root</tt> is the root, (ex.: http://www.example.com)
18
+ def self.site_root=(root)
19
+ @@site_root = root
20
+ end
21
+
22
+ # Initialize a map
23
+ #
24
+ # * <tt>file</tt> is the path to the (new or existent) sitemap.xml
25
+ def initialize(file)
26
+ @builder = REXML::Document.new(File.exists?(file)? File.read(file) : nil)
27
+ @locker = Mutex.new
28
+ @file = file
29
+ initialize_map
30
+ end
31
+
32
+ # Map the given localization
33
+ #
34
+ # <tt>loc</tt> is the URL to me mapped
35
+ # <tt>opts</tt> is a hash with the following parameters:
36
+ #
37
+ # * <tt>url</tt> or <tt>path</tt> is the complete URL or path (ex.: /articles/rails-doesnt-scale) [required]
38
+ # * <tt>lastmod</tt> a date object to the last modification [optional]
39
+ # * <tt>changefreq</tt> the frequency of change (:daily, :monthly, :yearly) [optional]
40
+ # * <tt>priority</tt> the priority of the URL (0..1) [optional]
41
+ #
42
+ # See http://www.sitemaps.org/protocol.php
43
+ def map_url(loc, opts={})
44
+ lastmod, changefreq, priority = extract_options(opts)
45
+ @locker.synchronize do
46
+ url = get_url(loc) || @builder.root.add_element('url')
47
+ (url.elements['loc'] || url.add_element('loc')).text = loc
48
+ (url.elements['lastmod'] || url.add_element('lastmod')).text = lastmod.strftime('%Y-%m-%d') if lastmod
49
+ (url.elements['changefreq'] || url.add_element('change_freq')).text = changefreq.to_s if changefreq
50
+ (url.elements['priority'] || url.add_element('priority')).text = '%.2f' % priority if priority
51
+
52
+ write_file
53
+ end
54
+ end
55
+
56
+ # Map the given path
57
+ #
58
+ # <tt>path</tt> is the path to be mapped
59
+ # <tt>opts</tt> is a hash containing options for this url (see <tt>map_url</tt>)
60
+ def map_path(path, opts={})
61
+ map_url(URI.join(Map.site_root, path), opts)
62
+ end
63
+
64
+ def map_urls #:nodoc:
65
+ # TODO: method to add various URLs and just write in the end
66
+ end
67
+
68
+ # Unmap the given localization (<tt>loc</tt>)
69
+ #
70
+ # * <tt>loc</tt> is the URL to be unmaped
71
+ def unmap_url(loc)
72
+ @locker.synchronize do
73
+ url = get_url(loc)
74
+ url.remove if url
75
+
76
+ write_file
77
+ end
78
+ end
79
+
80
+ # Unmap the given path
81
+ #
82
+ # * <tt>loc</tt> is the Path t be unmaped
83
+ def unmap_path(loc)
84
+ unmap_url(URI.join(Map.site_root, loc))
85
+ end
86
+
87
+ private
88
+
89
+ # Extract the options to map an URL
90
+ #
91
+ # see <tt>map_url</tt> to understand.
92
+ def extract_options(opts)
93
+ lastmod = opts.delete(:lastmod)
94
+ changefreq = opts.delete(:changefreq)
95
+ priority = opts.delete(:priority)
96
+
97
+ [lastmod, changefreq, priority]
98
+ end
99
+
100
+ # Return the Element for the given <tt>url</tt>
101
+ def get_url(url)
102
+ @builder.elements["//url[loc='#{url}']"]
103
+ end
104
+
105
+ # Write the file to disk (run only synchronized with @locker)
106
+ def write_file
107
+ File.open(@file, 'w') {|file| @builder.write(file, INDENT)}
108
+ end
109
+
110
+ # Initialize the map (called on the boot, normally)
111
+ def initialize_map
112
+ if @builder.root.nil?
113
+ @builder << REXML::XMLDecl.new('1.0', 'UTF-8')
114
+ @builder.add_element('urlset', 'xmlns' => SCHEMA)
115
+ else
116
+ raise InvalidMap unless @builder.root.attributes.key? 'xmlns'
117
+ end
118
+ end
119
+ end
120
+
121
+ class InvalidMap < StandardError; end
122
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :sitemaper do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,8 @@
1
+ require 'test/unit'
2
+
3
+ class SitemaperTest < Test::Unit::TestCase
4
+ # Replace this with your real tests.
5
+ def test_this_plugin
6
+ flunk
7
+ end
8
+ end
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sitemapper
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Carlos Junior
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-01-06 00:00:00 -02:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rails
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "2.1"
24
+ version:
25
+ description: Sitemapper helps you to apply SEO techniques on your Ruby on Rails application, including auto generation of a sitemap.
26
+ email:
27
+ - carlos@milk-it.net
28
+ executables: []
29
+
30
+ extensions: []
31
+
32
+ extra_rdoc_files:
33
+ - README.rdoc
34
+ - MIT-LICENSE
35
+ files:
36
+ - README.rdoc
37
+ - Rakefile
38
+ - MIT-LICENSE
39
+ - install.rb
40
+ - init.rb
41
+ - tasks/sitemaper_tasks.rake
42
+ - lib/sitemapper.rb
43
+ - lib/sitemapper/helpers.rb
44
+ - lib/sitemapper/map.rb
45
+ - lib/sitemapper/adapters/rails_adapter.rb
46
+ has_rdoc: true
47
+ homepage: http://redmine.milk-it.net/projects
48
+ post_install_message: |
49
+
50
+ Thank you for using Sitemapper.
51
+
52
+ Consider help us to maintain Sitemapper by donating (github.com/milk-it/sitemapper) if you like it!
53
+
54
+ rdoc_options:
55
+ - --line-numbers
56
+ - --inline-source
57
+ - --main
58
+ - README.rdoc
59
+ - --title
60
+ - Sitemapper
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: "0"
68
+ version:
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: "0"
74
+ version:
75
+ requirements: []
76
+
77
+ rubyforge_project: sitemapper
78
+ rubygems_version: 1.3.1
79
+ signing_key:
80
+ specification_version: 2
81
+ summary: Sitemapper helps you to apply SEO techniques on your Ruby on Rails application, including auto generation of a sitemap.
82
+ test_files:
83
+ - test/sitemapper_test.rb