sitemap 0.1b

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/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Daniel Mircea, The Geeks
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.
@@ -0,0 +1,21 @@
1
+ = Sitemap
2
+
3
+ A simple ruby on rails sitemap generator.
4
+
5
+ == Usage
6
+
7
+ Create a sitemap.rb file in your config directory. Paths can be indexed as follows:
8
+
9
+ Sitemap.instance.render :host => "mywebsite.com" do
10
+ path :root, :priority => 1
11
+ path :faq, :priority => 0.5, :change_frequency => "weekly"
12
+ resources :activities, :format => "html"
13
+ resources :articles, :objects => proc { Article.published }
14
+ end
15
+
16
+ Please read the docs for a more comprehensive list of options.
17
+
18
+ == License
19
+
20
+ This package is licensed under the MIT license and/or the Creative
21
+ Commons Attribution-ShareAlike.
@@ -0,0 +1,37 @@
1
+ require "rake/rdoctask"
2
+ require "rake/testtask"
3
+
4
+ spec = Gem::Specification.load(File.expand_path("sitemap.gemspec", File.dirname(__FILE__)))
5
+
6
+ desc "Default: run sitemap unit tests."
7
+ task :default => :test
8
+
9
+ desc "Test the sitemap plugin."
10
+ Rake::TestTask.new(:test) do |t|
11
+ t.libs << "lib"
12
+ t.pattern = "test/**/*_test.rb"
13
+ t.verbose = true
14
+ end
15
+
16
+ # Create the documentation.
17
+ Rake::RDocTask.new do |rdoc|
18
+ rdoc.rdoc_files.include "README.rdoc", "lib/**/*.rb"
19
+ rdoc.options = spec.rdoc_options
20
+ end
21
+
22
+ desc "Push new release to rubyforge and git tag"
23
+ task :push do
24
+ sh "git push"
25
+ puts "Tagging version #{spec.version} .."
26
+ sh "git tag v#{spec.version}"
27
+ sh "git push --tag"
28
+ puts "Building and pushing gem .."
29
+ sh "gem build #{spec.name}.gemspec"
30
+ sh "gem push #{spec.name}-#{spec.version}.gem"
31
+ end
32
+
33
+ desc "Install #{spec.name} locally"
34
+ task :install do
35
+ sh "gem build #{spec.name}.gemspec"
36
+ sh "gem install #{spec.name}-#{spec.version}.gem"
37
+ end
@@ -0,0 +1,168 @@
1
+ #
2
+ # = sitemap.rb - Sitemap
3
+ #
4
+ # Author:: Daniel Mircea daniel@viseztrance.com
5
+ # Copyright:: 2011 (c) Daniel Mircea, {The Geeks}[http://thegeeks.ro]
6
+ # License:: MIT and/or Creative Commons Attribution-ShareAlike
7
+
8
+ require "singleton"
9
+ require "builder"
10
+ require "sitemap/railtie"
11
+ require "sitemap/ping"
12
+
13
+ module Sitemap
14
+
15
+ VERSION = Gem::Specification.load(File.expand_path("../sitemap.gemspec", File.dirname(__FILE__))).version.to_s
16
+
17
+ mattr_accessor :defaults
18
+
19
+ self.defaults = {
20
+ :params => {},
21
+ :search => {
22
+ :updated_at => proc { |obj| obj.updated_at.strftime("%Y-%m-%d") if obj.respond_to?(:updated_at) }
23
+ }
24
+ }
25
+
26
+ class Generator
27
+
28
+ include Singleton
29
+
30
+ SEARCH_ATTRIBUTES = {
31
+ :updated_at => "lastmod",
32
+ :change_frequency => "changefreq",
33
+ :priority => "priority"
34
+ }
35
+
36
+ attr_accessor :entries, :host, :routes
37
+
38
+ # Instantiates a new object.
39
+ # Should never be called directly.
40
+ def initialize
41
+ self.class.send(:include, Rails.application.routes.url_helpers)
42
+ self.entries = []
43
+ end
44
+
45
+ # Sets the urls to be indexed.
46
+ #
47
+ # The +host+, or any other global option can be set here:
48
+ #
49
+ # Sitemap.instance.render :host => "mywebsite.com" do
50
+ # ...
51
+ # end
52
+ #
53
+ # Simple paths can be added as follows:
54
+ #
55
+ # Sitemap.instance.render :host => "mywebsite.com" do
56
+ # path :faq
57
+ # end
58
+ #
59
+ # Object collections are supported too:
60
+ #
61
+ # Sitemap.instance.render :host => "mywebsite.com" do
62
+ # resources :activities
63
+ # end
64
+ #
65
+ # Search options such as frequency and priority can be declared as an options hash:
66
+ #
67
+ # Sitemap.instance.render :host => "mywebsite.com" do
68
+ # path :root, :priority => 1
69
+ # path :faq, :priority => 0.8, :change_frequency => "daily"
70
+ # resources :activities, :change_frequency => "weekly"
71
+ # end
72
+ #
73
+ def render(options = {}, &block)
74
+ options.each do |k, v|
75
+ self.send("#{k}=", v)
76
+ end
77
+ self.routes = block
78
+ end
79
+
80
+ # Adds the specified url or object (such as an ActiveRecord model instance).
81
+ # In either case the data is being looked up in the current application routes.
82
+ #
83
+ # Params can be specified as follows:
84
+ #
85
+ # # config/routes.rb
86
+ # match "/frequent-questions" => "static#faq", :as => "faq"
87
+ #
88
+ # # config/sitemap.rb
89
+ # path :faq, :params => { :filter => "recent" }
90
+ #
91
+ # The resolved url would be <tt>http://mywebsite.com/frequent-questions?filter=recent</tt>.
92
+ #
93
+ def path(object, options = {})
94
+ params = Sitemap.defaults[:params].clone.merge!(options[:params] || {})
95
+ params[:host] ||= host # Use global host if none was specified.
96
+ params.merge!(params) { |type, value| get_data(object, value) }
97
+
98
+ search = Sitemap.defaults[:search].clone.merge!(options.select { |k, v| SEARCH_ATTRIBUTES.keys.include?(k) })
99
+ search.merge!(search) { |type, value| get_data(object, value) }
100
+
101
+ self.entries << {
102
+ :object => object,
103
+ :search => search,
104
+ :params => params
105
+ }
106
+ end
107
+
108
+ # Adds the associated object types.
109
+ #
110
+ # The following will map all Activity entries, as well as the index (<tt>/activities</tt>) page:
111
+ #
112
+ # resources :activities
113
+ #
114
+ # You can also specify which entries are being mapped:
115
+ #
116
+ # resources :articles, :objects => proc { Article.published }
117
+ #
118
+ # To skip the index action and map only the records:
119
+ #
120
+ # resources :articles, :skip_index => true
121
+ #
122
+ # As with the path, you can specify params through the +params+ options hash.
123
+ # The params can also be build conditionally by using a +proc+:
124
+ #
125
+ # resources :activities, :params => { :host => proc { |activity| [activity.location, host].join(".") } }, :skip_index => true
126
+ #
127
+ # In this case the host will change based the each of the objects associated +location+ attribute.
128
+ # Because the index page doesn't have this attribute it's best to skip it.
129
+ #
130
+ def resources(type, options = {})
131
+ path(type) unless options[:skip_index]
132
+ objects = options[:objects] ? options[:objects].call : type.to_s.classify.constantize.all
133
+ options.reject! { |k, v| k == :objects }
134
+
135
+ objects.each do |object|
136
+ path(object, options)
137
+ end
138
+ end
139
+
140
+ # Parses the loaded data and returns the xml entries.
141
+ def build
142
+ instance_exec(self, &routes)
143
+ xml = Builder::XmlMarkup.new(:indent => 2)
144
+ file = File.read(File.expand_path("../views/index.xml.builder", __FILE__))
145
+ instance_eval file
146
+ end
147
+
148
+ # Builds xml entries and saves the data to the specified location.
149
+ def save(location)
150
+ file = File.new(location, "w")
151
+ file.write(build)
152
+ file.close
153
+ end
154
+
155
+ # URL to the <tt>sitemap.xml</tt> file.
156
+ def file_url
157
+ URI::HTTP.build(:host => host, :path => "/sitemap.xml").to_s
158
+ end
159
+
160
+ private
161
+
162
+ def get_data(object, data)
163
+ data.respond_to?(:call) ? data.call(object) : data
164
+ end
165
+
166
+ end
167
+
168
+ end
@@ -0,0 +1,24 @@
1
+ require "net/http"
2
+ require "cgi"
3
+
4
+ module Sitemap
5
+
6
+ module Ping
7
+
8
+ SEARCH_ENGINES = {
9
+ "Google" => "http://www.google.com/webmasters/tools/ping?sitemap=%s",
10
+ "Yahoo!" => "http://search.yahooapis.com/SiteExplorerService/V1/updateNotification?appid=SitemapWriter&url=%s",
11
+ "Ask.com" => "http://submissions.ask.com/ping?sitemap=%s",
12
+ "Bing" => "http://www.bing.com/webmaster/ping.aspx?siteMap=%s"
13
+ }
14
+
15
+ def self.send_request(file_path = false)
16
+ SEARCH_ENGINES.each do |name, url|
17
+ request = url % CGI.escape(file_path || Sitemap::Generator.instance.file_url)
18
+ Net::HTTP.get(URI.parse(request))
19
+ end
20
+ end
21
+
22
+ end
23
+
24
+ end
@@ -0,0 +1,13 @@
1
+ require "rails"
2
+
3
+ module Sitemap
4
+
5
+ class Railtie < Rails::Railtie
6
+
7
+ rake_tasks do
8
+ load "tasks/sitemap.rake"
9
+ end
10
+
11
+ end
12
+
13
+ end
@@ -0,0 +1,19 @@
1
+ namespace :sitemap do
2
+
3
+ def setup
4
+ require File.join(Rails.root, "config", "sitemap")
5
+ end
6
+
7
+ desc "Generates a new sitemap."
8
+ task :generate => :environment do
9
+ setup
10
+ path = File.join(Rails.public_path, "sitemap.xml")
11
+ Sitemap::Generator.instance.save path
12
+ end
13
+
14
+ desc "Ping engines."
15
+ task :ping => :environment do
16
+ Sitemap::Ping.send_request ENV["LOCATION"]
17
+ end
18
+
19
+ end
@@ -0,0 +1,15 @@
1
+ xml.instruct!
2
+ xml.urlset :xmlns => "http://www.sitemaps.org/schemas/sitemap/0.9" do
3
+
4
+ entries.each do |entry|
5
+ xml.url do
6
+ xml.loc polymorphic_url(entry[:object], entry[:params])
7
+ entry[:search].each do |type, value|
8
+ next if !value || value.blank?
9
+ xml.tag! SEARCH_ATTRIBUTES[type], value.to_s
10
+ end
11
+ end
12
+ end
13
+
14
+ end
15
+
@@ -0,0 +1,24 @@
1
+ $LOAD_PATH << File.join(File.dirname(__FILE__), "lib")
2
+
3
+ spec = Gem::Specification.new do |spec|
4
+ spec.name = "sitemap"
5
+ spec.version = "0.1b"
6
+ spec.summary = "Sitemap"
7
+ spec.description = "A simple ruby on rails sitemap generator"
8
+
9
+ spec.authors << "Daniel Mircea"
10
+ spec.email = "daniel@viseztrance.com"
11
+ spec.homepage = "http://github.com/viseztrance/rails-sitemap"
12
+
13
+ spec.add_development_dependency "sqlite3"
14
+ spec.add_development_dependency "nokogiri"
15
+
16
+ spec.files = Dir["{lib,docs}/**/*"] + ["README.rdoc", "LICENSE", "Rakefile", "sitemap.gemspec"]
17
+ spec.test_files = Dir["test/**/*"]
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.has_rdoc = true
21
+ spec.rdoc_options << "--main" << "README.rdoc" << "--title" << "Sitemap" << "--line-numbers"
22
+ "--webcvs" << "http://github.com/viseztrance/rails-sitemap"
23
+ spec.extra_rdoc_files = ["README.rdoc", "LICENSE"]
24
+ end
@@ -0,0 +1,49 @@
1
+ module TestApp
2
+
3
+ class Application < Rails::Application
4
+ config.active_support.deprecation = :log
5
+ end
6
+
7
+ end
8
+
9
+ TestApp::Application.initialize!
10
+
11
+ TestApp::Application.routes.draw do
12
+
13
+ root :to => "main#index"
14
+
15
+ match "/questions" => "static#faq", :as => "faq"
16
+
17
+ resources :activities
18
+
19
+ end
20
+
21
+ module SitemapTestSetup
22
+
23
+ def create_db
24
+ # Database
25
+ ActiveRecord::Schema.define(:version => 1) do
26
+ create_table :activities do |t|
27
+ t.string :name
28
+ t.text :contents
29
+ t.string :location
30
+ t.timestamps
31
+ end
32
+ end
33
+ 1.upto(8) do |i|
34
+ options = {
35
+ :name => "Coding #{i}",
36
+ :contents => "Lorem ipsum dolor sit",
37
+ :location => "someplace-#{i}"
38
+ }
39
+ Activity.create!(options)
40
+ end
41
+ end
42
+
43
+ def drop_db
44
+ ActiveRecord::Base.connection.tables.each do |table|
45
+ ActiveRecord::Base.connection.drop_table(table)
46
+ end
47
+ end
48
+
49
+ end
@@ -0,0 +1,24 @@
1
+ # Reset singleton
2
+ # http://blog.ardes.com/2006/12/11/testing-singletons-with-ruby
3
+ class << Singleton
4
+
5
+ def included_with_reset(klass)
6
+
7
+ included_without_reset(klass)
8
+
9
+ class << klass
10
+
11
+ def reset_instance
12
+ Singleton.send :__init__, self
13
+ self
14
+ end
15
+
16
+ end
17
+
18
+ end
19
+
20
+ alias_method :included_without_reset, :included
21
+
22
+ alias_method :included, :included_with_reset
23
+
24
+ end
@@ -0,0 +1,139 @@
1
+ require "test/unit"
2
+ require "rubygems"
3
+ require "rails"
4
+ require "action_controller/railtie" # Rails 3.1
5
+ require "active_record"
6
+ require "nokogiri"
7
+
8
+ require File.expand_path("singleton", File.dirname(__FILE__))
9
+ require File.expand_path("setup", File.dirname(__FILE__))
10
+ require File.expand_path("../lib/sitemap", File.dirname(__FILE__))
11
+
12
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
13
+
14
+ class Activity < ActiveRecord::Base; end
15
+
16
+ class SitemapTest < Test::Unit::TestCase
17
+
18
+ include SitemapTestSetup
19
+
20
+ def setup
21
+ create_db
22
+ Sitemap::Generator.reset_instance
23
+ end
24
+
25
+ def teardown
26
+ drop_db
27
+ end
28
+
29
+ def test_xml_response
30
+ Sitemap::Generator.instance.render(:host => "someplace.com") {}
31
+ doc = Nokogiri::XML(Sitemap::Generator.instance.build)
32
+ assert doc.errors.empty?
33
+ assert_equal doc.root.name, "urlset"
34
+ end
35
+
36
+ def test_path_route
37
+ urls = ["http://someplace.com/", "http://someplace.com/questions"]
38
+ Sitemap::Generator.instance.render(:host => "someplace.com") do
39
+ path :root
40
+ path :faq
41
+ end
42
+ doc = Nokogiri::HTML(Sitemap::Generator.instance.build)
43
+ elements = doc.xpath "//url/loc"
44
+ assert_equal elements.length, urls.length
45
+ elements.each_with_index do |element, i|
46
+ assert_equal element.text, urls[i]
47
+ end
48
+ end
49
+
50
+ def test_resources_route
51
+ Sitemap::Generator.instance.render(:host => "someplace.com") do
52
+ resources :activities
53
+ end
54
+ doc = Nokogiri::HTML(Sitemap::Generator.instance.build)
55
+ elements = doc.xpath "//url/loc"
56
+ assert_equal elements.length, Activity.count + 1
57
+ assert_equal elements.first.text, "http://someplace.com/activities"
58
+ elements[1..-1].each_with_index do |element, i|
59
+ assert_equal element.text, "http://someplace.com/activities/#{i + 1}"
60
+ end
61
+ end
62
+
63
+ def test_custom_resource_objects
64
+ activities = [Activity.first, Activity.last]
65
+ Sitemap::Generator.instance.render(:host => "someplace.com") do
66
+ resources :activities, :objects => proc { activities }, :skip_index => true
67
+ end
68
+ doc = Nokogiri::HTML(Sitemap::Generator.instance.build)
69
+ elements = doc.xpath "//url/loc"
70
+ assert_equal elements.length, activities.length
71
+ activities.each_with_index do |activity, i|
72
+ assert_equal elements[i].text, "http://someplace.com/activities/%d" % activity.id
73
+ end
74
+ end
75
+
76
+ def test_params_options
77
+ Sitemap::Generator.instance.render(:host => "someplace.com") do
78
+ path :faq, :params => { :host => "anotherplace.com", :format => "html", :filter => "recent" }
79
+ end
80
+ doc = Nokogiri::HTML(Sitemap::Generator.instance.build)
81
+ elements = doc.xpath "//url/loc"
82
+ assert_equal elements.first.text, "http://anotherplace.com/questions.html?filter=recent"
83
+ end
84
+
85
+ def test_params_blocks
86
+ Sitemap::Generator.instance.render(:host => "someplace.com") do
87
+ resources :activities, :skip_index => true, :params => { :host => proc { |obj| [obj.location, host].join(".") } }
88
+ end
89
+ activities = Activity.all
90
+ doc = Nokogiri::HTML(Sitemap::Generator.instance.build)
91
+ elements = doc.xpath "//url/loc"
92
+ elements.each_with_index do |element, i|
93
+ assert_equal element.text, "http://%s.someplace.com/activities/%d" % [activities[i].location, activities[i].id]
94
+ end
95
+ end
96
+
97
+ def test_search_attribute_options
98
+ Sitemap::Generator.instance.render(:host => "someplace.com") do
99
+ path :faq, :priority => 1, :change_frequency => "always"
100
+ resources :activities, :change_frequency => "weekly"
101
+ end
102
+ doc = Nokogiri::HTML(Sitemap::Generator.instance.build)
103
+ assert_equal doc.xpath("//url/priority").first.text, "1"
104
+ elements = doc.xpath "//url/changefreq"
105
+ assert_equal elements[0].text, "always"
106
+ elements[1..-1].each do |element|
107
+ assert_equal element.text, "weekly"
108
+ end
109
+ end
110
+
111
+ def test_search_attribute_blocks
112
+ Sitemap::Generator.instance.render(:host => "someplace.com") do
113
+ resources :activities, :priority => proc { |obj| obj.id <= 2 ? 1 : 0.5 }, :skip_index => true
114
+ end
115
+ activities = Activity.all
116
+ doc = Nokogiri::HTML(Sitemap::Generator.instance.build)
117
+ elements = doc.xpath "//url/priority"
118
+ elements.each_with_index do |element, i|
119
+ value = activities[i].id <= 2 ? "1" : "0.5"
120
+ assert_equal element.text, value
121
+ end
122
+ end
123
+
124
+ def test_discards_empty_search_attributes # Empty or false (boolean).
125
+ Sitemap::Generator.instance.render(:host => "someplace.com") do
126
+ path :faq, :priority => "", :change_frequency => lambda { |e| return false}, :updated_at => Date.today
127
+ end
128
+ doc = Nokogiri::HTML(Sitemap::Generator.instance.build)
129
+ assert_equal doc.xpath("//url/priority").count, 0
130
+ assert_equal doc.xpath("//url/changefreq").count, 0
131
+ assert_equal doc.xpath("//url/lastmod").text, Date.today.to_s
132
+ end
133
+
134
+ def test_file_url
135
+ Sitemap::Generator.instance.render(:host => "someplace.com") {}
136
+ assert_equal Sitemap::Generator.instance.file_url, "http://someplace.com/sitemap.xml"
137
+ end
138
+
139
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sitemap
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1b
5
+ prerelease: 3
6
+ platform: ruby
7
+ authors:
8
+ - Daniel Mircea
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-09-03 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: sqlite3
16
+ requirement: &24552460 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *24552460
25
+ - !ruby/object:Gem::Dependency
26
+ name: nokogiri
27
+ requirement: &24552040 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *24552040
36
+ description: A simple ruby on rails sitemap generator
37
+ email: daniel@viseztrance.com
38
+ executables: []
39
+ extensions: []
40
+ extra_rdoc_files:
41
+ - README.rdoc
42
+ - LICENSE
43
+ files:
44
+ - lib/views/index.xml.builder
45
+ - lib/sitemap.rb
46
+ - lib/sitemap/railtie.rb
47
+ - lib/sitemap/ping.rb
48
+ - lib/tasks/sitemap.rake
49
+ - README.rdoc
50
+ - LICENSE
51
+ - Rakefile
52
+ - sitemap.gemspec
53
+ - test/singleton.rb
54
+ - test/setup.rb
55
+ - test/sitemap_test.rb
56
+ homepage: http://github.com/viseztrance/rails-sitemap
57
+ licenses: []
58
+ post_install_message:
59
+ rdoc_options:
60
+ - --main
61
+ - README.rdoc
62
+ - --title
63
+ - Sitemap
64
+ - --line-numbers
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ! '>='
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>'
77
+ - !ruby/object:Gem::Version
78
+ version: 1.3.1
79
+ requirements: []
80
+ rubyforge_project:
81
+ rubygems_version: 1.8.8
82
+ signing_key:
83
+ specification_version: 3
84
+ summary: Sitemap
85
+ test_files:
86
+ - test/singleton.rb
87
+ - test/setup.rb
88
+ - test/sitemap_test.rb