manage_meta 0.0.4

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 2011 YOURNAME
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.markdown ADDED
@@ -0,0 +1,132 @@
1
+ ManageMeta
2
+ ============
3
+
4
+ ManageMeta is yet another meta tag manager for Rails 3.x. Its features are: recognizes tags
5
+ should render as HTTP-EQUIV; supports the Google 'canonical' link; is extensible; is non-intrusive
6
+
7
+ How it works
8
+ -----------
9
+
10
+ Include the gem by adding this to your Gemfile file
11
+
12
+ `gem "manage_meta", :git => "git://github.com/mikehoward/manage_meta.git"`
13
+
14
+ Then, in your controller actions, call _add_meta_ for each meta tag you want
15
+ to define.
16
+
17
+ `add_meta :author, 'Fred Fink'`
18
+
19
+ If there are meta tags you don't want to define, you can use _del_meta_ to remove them.
20
+ At present there are only two automatically defined: 'robots' and 'generator'. You may
21
+ also redefine them by using _add_meta_ to give them new values.
22
+
23
+ If there is a meta tag which requires a currently unsupported format, you may add it
24
+ using _add_meta_format_.
25
+
26
+ Finally, edit app/views/layouts/application.html.erb - or equivalent - to insert
27
+
28
+ `<%= render_meta %>`
29
+
30
+ into the _head_ section of your HTML output. This will render and return all of the
31
+ defined meta tags.
32
+
33
+ What it Adds
34
+ ------------
35
+
36
+ ManageMeta defines four (4) methods and three (3) instance variables into all classes
37
+ derived from ApplicationController
38
+
39
+ The methods are:
40
+
41
+ * add_meta - adds a meta tag
42
+ * del_meta - which deletes a meta tag
43
+ * add_meta_format - which adds a meta tag format
44
+ * render_meta - which returns a string rendering all currently defined meta tags.
45
+
46
+ The instance variables are:
47
+
48
+ * @manage_meta_meta_hash - a Hash containing mapping defined meta tag names to content values
49
+ * @manage_meta_format_hash - a Hash mapping known meta tag format strings to actual format strings
50
+ * @manage_meta_name_to_format - a Hash mapping meta tag name strings to known formats
51
+
52
+ The Details
53
+ --------------
54
+
55
+ Here are the ugly details
56
+
57
+ ### Methods in Detail ###
58
+
59
+ #### add_meta ####
60
+
61
+ _add_meta_ accepts values in any of three formats:
62
+
63
+ `add_meta(name, value[, :format => :format_name])`
64
+ `add_meta(name, value[, :format => :format_name]) do ... end`
65
+ `add_meta(name[, :format => :format_name]) do ... end`
66
+
67
+ * name must be something which responds to 'to_s'. It will be used for the _name_ (or _http-equiv_)
68
+ attribute of the meta tag.
69
+ * value must be something which responds to 'to_s' and is not a Hash. Normally it will simply
70
+ be a string. If given, it supplies the leading part of the _content_ attribute of the meta tag
71
+ * The single option :format must supply an existing key in @manage_meta_format_hash. It is
72
+ used to associate a meta tag format with _name_. If not given and not currently defined in
73
+ @manage_meta_format_hash, it will be set to _:named_. (see below for details)
74
+ * The optional block is evaluated and the return value is used as the second [or only] part
75
+ of the _content_ attribute of the meta tag.
76
+
77
+ Three meta tag formats are defined automatically:
78
+
79
+ * `:named => '<meta name="#{name}" content="#{content}" char-encoding="utf-8" />'`
80
+ * `:http_equiv => '<meta http-equiv="#{name}" content="#{content}" char-encoding="utf-8" />'`
81
+ * `:canonical => '<link rel="canonical" href="#{content}" />'`
82
+
83
+ The _@manage_meta_name_to_format_ is populated with entries mapping known HTTP-EQUIV tags
84
+ and the CANONICAL Google link tag to the correct format.
85
+
86
+ #### del_meta ####
87
+
88
+ _del_meta_ is almost useless. It's there in case you want to get ride of a default tag.
89
+
90
+ `del_meta(name)`
91
+
92
+ where _name_ is something which responds to 'to_s' [or is a string]. If the meta tag is
93
+ defined in @manage_meta_meta_hash, then it will be deleted. Nothing bad happens if it isn't.
94
+
95
+ #### add_meta_format_ ####
96
+
97
+ `add_meta_format(format_name, format_string)`
98
+
99
+ _format_name__ will be converted to a symbol.
100
+
101
+ _format_string_ will be the value of @manage_meta_format_hash[_format_name.to_sym_].
102
+
103
+ It's your responsibility to format the string properly.
104
+
105
+ _render_meta_ will replace _name_ and _content_ with the string values given for the meta
106
+ tag - if present. It is not an error to omit either or both _name_ and/or _content_
107
+
108
+ #### render_meta ####
109
+
110
+ `render_meta`
111
+
112
+ simply goes through all the defined key, value pairs in @manage_meta_meta_hash and
113
+ returns their associated format strings after replacing the _#{name}_ and _#{content}_
114
+ symbols with their values.
115
+
116
+ ### Instance Variables in Detail ###
117
+
118
+ #### manage_meta_format_hash ####
119
+
120
+ keys are symbols,
121
+
122
+ values are strings which are used to render meta tags
123
+
124
+ #### manage_meta_meta_hash ####
125
+
126
+ keys are strings which are used for the names of meta tags
127
+
128
+ values are symbols which are keys in @manage_meta_format_hash
129
+
130
+ #### manage_meta_name_to_format ####
131
+
132
+ keys are strings which map meta tag names to keys in @manage_meta_format_hash
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ require 'rake'
2
+
3
+ task :default => :test
4
+
5
+ desc "Run ManageMeta unit tests"
6
+ task :test do
7
+ require './test/manage_meta_test'
8
+ end
9
+
10
+ desc "run rdoc to create doc"
11
+ task :doc do
12
+ system 'rdoc'
13
+ end
14
+
15
+ desc "build gem"
16
+ task :gem do
17
+ system 'gem build manage_meta.gemspec'
18
+ end
@@ -0,0 +1,7 @@
1
+ require 'manage_meta/manage_meta'
2
+
3
+ if defined? Rails
4
+ class ApplicationController < ActionController::Base
5
+ include ManageMeta
6
+ end
7
+ end
@@ -0,0 +1,131 @@
1
+ module ManageMeta
2
+ def self.included(mod)
3
+ # OK this is a hack based on section 25.4 of Programming Ruby 1.9 by Dave Thomas
4
+ # we are using the _included_ hook from Ruby's Module module to run some code
5
+ # which replaces the 'initialize' routine with one which creates our required instance
6
+ # data.
7
+ # 1. We are saving the original 'initialize' as old_initialize.
8
+ # 2. we execute the private method 'define_method' via mod.send which has the side effect
9
+ # of carrying the definition of 'old_initialize' into the closure.
10
+ # 3. we have to bind 'old_initialize' to the run-time value of 'self' because it is an unbound
11
+ # method and 'self' will have the right value when it is run in the context of 'mod' creating
12
+ # an instance
13
+ # 4. we then define our instance variables so that everything will work properly
14
+
15
+ mod.helper_method :render_meta if mod.respond_to? :helper_method
16
+
17
+ old_initialize = mod.instance_method :initialize
18
+ mod.send(:define_method, :initialize) do |*args, &block|
19
+ result = old_initialize.bind(self).call(*args, &block)
20
+ @manage_meta_meta_hash = {}
21
+
22
+ @manage_meta_format_hash = {
23
+ :named => '<meta name="#{name}" content="#{content}" char-encoding="utf-8" />',
24
+ :http_equiv => '<meta http-equiv="#{name}" content="#{content}" char-encoding="utf-8" />',
25
+ :canonical => '<link rel="canonical" href="#{content}" />',
26
+ }
27
+
28
+ @manage_meta_name_to_format = {}
29
+ #-- set up http-equiv meta tags
30
+ ['accept', 'accept-charset', 'accept-encoding', 'accept-language', 'accept-ranges',
31
+ 'age', 'allow', 'authorization', 'cache-control', 'connecting', 'content-encoding',
32
+ 'content-language', 'content-length', 'content-location', 'content-md5', 'content-range',
33
+ 'content-type', 'date', 'etag', 'expect', 'expires', 'from', 'host', 'if-match', 'if-modified-since',
34
+ 'if-none-match', 'if-range', 'if-unmodified-since', 'last-modified', 'location',
35
+ 'max-forwards', 'pragma', 'proxy-authenticate', 'proxy-authorization', 'range', 'referer',
36
+ 'retry-after', 'server', 'te', 'trailer', 'transfer-encoding', 'upgrade', 'user-agent',
37
+ 'vary', 'via', 'warning', 'www-authenticate', ].each { |name| @manage_meta_name_to_format[name] = :http_equiv }
38
+ # set up Google's canonical link tag
39
+ ['canonical'].each { |name| @manage_meta_name_to_format[name] = :canonical }
40
+ # set up normal meta tags
41
+ ['description', 'keywords', 'language', 'robots'].each { |name| @manage_meta_name_to_format[name] = :named }
42
+
43
+ add_meta 'robots', 'index follow'
44
+ add_meta 'generator', "Rails #{Rails.version}" if defined?(Rails)
45
+ # add_meta 'canonical', request.fullpath
46
+ result
47
+ end
48
+ end
49
+
50
+ #--
51
+ protected
52
+
53
+ #++
54
+ # add_meta(name, value[, options]) - adds meta tag 'name' with value 'value' to meta tags to be displayed
55
+ # add_meta(name[, options] &block) - does same thing, except value is the return value of &block
56
+ # Note: if no both 'value' and 'block' are given, then the content of the meta tag is the concatenation
57
+ # of both values.
58
+ # options:
59
+ # :format => symbol - where 'symbol' is one of :named, :http_equiv, :canonical, or a format
60
+ # added with 'add_meta_format'
61
+ # all other options keys are ignored
62
+ #--
63
+ def add_meta(name, opt_value = nil, options = {}, &block)
64
+ # make sure name is a string
65
+ name = name.to_s
66
+
67
+ # handle optional nonsense
68
+ case
69
+ when opt_value.is_a?(String)
70
+ value = opt_value
71
+ value += yield.to_s if block_given?
72
+ when opt_value.is_a?(Hash)
73
+ raise ArgumentError, "Value for meta tag #{name} missing" if !block_given?
74
+ value = yield.to_s
75
+ options = opt_value
76
+ when opt_value.nil?
77
+ raise ArgumentError, "Value for meta tag #{name} missing" if !block_given?
78
+ value = yield.to_s
79
+ when opt_value.respond_to?(:to_s)
80
+ value = opt_value.to_s
81
+ value += yield.to_s if block_given?
82
+ else
83
+ raise ArgumentError, "add_meta(name, value[, options hash]) or add_meta(name[, option hash] do ... end)"
84
+ end
85
+ @manage_meta_meta_hash[name] = value
86
+
87
+ if (options.keys - [:format]).size > 0
88
+ raise RuntimeError, "add_meta(#{name}, ...): illegal option key(s): #{options.keys - [:format]}"
89
+ end
90
+
91
+ # if format is explicitly called out or if name is not yet known
92
+ if options.has_key?(:format)
93
+ raise RuntimeError, "Unsuported Format: #{options[:format]}: formats are #{@manage_meta_format_hash.keys.join(',')}" if !@manage_meta_format_hash.has_key?(options[:format].to_sym)
94
+ @manage_meta_name_to_format[name] = options[:format].to_sym
95
+ elsif !@manage_meta_name_to_format.has_key?(name)
96
+ @manage_meta_name_to_format[name] = :named
97
+ end
98
+ end
99
+
100
+ #++
101
+ # del_meta(name) - where _name_ is a string or a symbol.
102
+ #
103
+ # if _name_ is in @manage_meta_meta_hash, then it will be deleted
104
+ #--
105
+ def del_meta(name)
106
+ name = name.to_s
107
+ @manage_meta_meta_hash.delete name if @manage_meta_meta_hash.has_key? name
108
+ end
109
+
110
+ #++
111
+ # add_meta_format(key, format)
112
+ #
113
+ # adds the format _format_ to @manage_meta_format_hash using the key _key_
114
+ #--
115
+ def add_meta_format(key, format)
116
+ key = key.to_sym
117
+ @manage_meta_format_hash[key] = format
118
+ end
119
+
120
+ #++
121
+ # render_meta
122
+ #
123
+ # returns a string consisting of all defined meta names in @manage_meta_meta_hash, formatted
124
+ # using their name-specific formats and indented two spaces.
125
+ #--
126
+ def render_meta
127
+ ' ' + @manage_meta_meta_hash.map do |name, content|
128
+ @manage_meta_format_hash[@manage_meta_name_to_format[name]].sub('#{name}', name).sub('#{content}', content)
129
+ end.join("\n ") + " \n"
130
+ end
131
+ end
@@ -0,0 +1,116 @@
1
+ $LOAD_PATH << File.expand_path("../../lib", __FILE__)
2
+ require 'test/unit'
3
+ require 'manage_meta'
4
+
5
+ class ManageMetaTest < Test::Unit::TestCase
6
+ include ManageMeta
7
+
8
+ class NoToS ; end
9
+ NoToS.send :undef_method, :to_s
10
+
11
+ # add refute methods for ruby 1.8.7
12
+ if !self.instance_methods.include? :refute_respond_to
13
+ def refute_respond_to(obj, func, msg = nil)
14
+ assert ! obj.respond_to?( func, msg )
15
+ end
16
+
17
+ def refute(expr, msg = nil)
18
+ assert ! expr, msg
19
+ end
20
+ end
21
+
22
+ # test 'existence of add_meta method' do
23
+ def test_methods_exist
24
+ assert_respond_to self, :add_meta, "responds to add_meta()"
25
+ assert_respond_to self, :del_meta, "responds to del_meta()"
26
+ assert_respond_to self, :add_meta_format, "responds to add_meta_format()"
27
+ assert_respond_to self, :render_meta, "responds to render_meta()"
28
+ end
29
+
30
+ # add_meta tests
31
+ # test "add_meta argument edge cases" do
32
+ def test_add_meta_edge_cases
33
+
34
+ assert_raise(ArgumentError, "name of meta must be present") { add_meta }
35
+ assert_raise(ArgumentError, "value must be present") { add_meta :foo }
36
+ assert_raise(ArgumentError, "value must not be nil") { add_meta :foo, nil }
37
+ assert_raise(ArgumentError, "value must not be a hash") { add_meta :foo, :hash => true }
38
+
39
+ # make sure fails if value does not respond to :to_s
40
+ no_to_s = NoToS.new
41
+ refute_respond_to no_to_s, :to_s, "no_to_s must not respond to 'to_s'"
42
+ assert_raise(ArgumentError, "value must respond to to_s") { add_meta :no_to_s, no_to_s }
43
+
44
+ assert_raise(RuntimeError, "illegal option must raise an error") { add_meta :foo, 'value', :bad_opt => 'stuff'}
45
+ end
46
+
47
+ # test "add_meta adds methods to meta_hash" do
48
+ def test_add_meta_adds_meta
49
+ assert_nothing_raised(Exception, "add_meta foo, bar is ok") { add_meta :foo, "bar" }
50
+ assert self.instance_variable_get("@manage_meta_meta_hash").key?('foo'),
51
+ "meta variable 'foo' not defined #{self.instance_variable_get('@manage_meta_meta_hash')}"
52
+ assert self.instance_variable_get("@manage_meta_meta_hash")['foo'] == 'bar',
53
+ "meta variable 'foo' not defined #{self.instance_variable_get('@manage_meta_meta_hash')}"
54
+ assert_nothing_raised(Exception, "add_meta(bar) {'value'}") { add_meta( :bar ) { 'value' }}
55
+ assert self.instance_variable_get("@manage_meta_meta_hash").key?('bar'),
56
+ "meta variable 'bar' not defined #{self.instance_variable_get('@manage_meta_meta_hash')}"
57
+ assert self.instance_variable_get("@manage_meta_meta_hash")['bar'] == 'value',
58
+ "meta variable 'bar' not defined #{self.instance_variable_get('@manage_meta_meta_hash')}"
59
+ end
60
+
61
+ # test "add_meta concatenates value and output of block" do
62
+ def test_add_meta_concats_value_and_block
63
+ add_meta(:foo, 'arg value') { ' block value' }
64
+ assert_equal self.instance_variable_get("@manage_meta_meta_hash")['foo'], 'arg value block value',
65
+ "add meta must concatenate value of both arg value and output of block"
66
+ add_meta(:foo, 'arg value', :format => :canonical) { ' block value' }
67
+ assert_equal self.instance_variable_get("@manage_meta_meta_hash")['foo'], 'arg value block value',
68
+ "add meta must concatenate value of both arg value and output of block with option present"
69
+ end
70
+
71
+ # test "add_meta with :format argument" do
72
+ def test_add_meta_format_works
73
+ # bad format option
74
+ assert_raise(RuntimeError, "Must not accept undefined format") { add_meta :foo, 'value', :format => :bad_key }
75
+ # good format options
76
+ assert_nothing_raised("Must accept format arg as string") { add_meta :foo, 'value', :format => 'named' }
77
+ end
78
+
79
+ # test ' del_meta' do
80
+ def test_del_meta_deletes_meta_tag
81
+ assert_nothing_raised(Exception, "add_meta foo, bar is ok") { add_meta :foo, "bar" }
82
+ assert self.instance_variable_get("@manage_meta_meta_hash").key?('foo'),
83
+ "meta variable 'foo' not defined #{self.instance_variable_get('@manage_meta_meta_hash')}"
84
+ assert self.instance_variable_get("@manage_meta_meta_hash")['foo'] == 'bar',
85
+ "meta variable 'foo' not defined #{self.instance_variable_get('@manage_meta_meta_hash')}"
86
+ del_meta(:foo)
87
+ refute self.instance_variable_get("@manage_meta_meta_hash").key?('foo'),
88
+ "meta variable 'foo' should not be defined #{self.instance_variable_get('@manage_meta_meta_hash')}"
89
+ end
90
+
91
+ # test 'add_meta_format' do
92
+ def test_add_meta_format_adds_a_format
93
+ format = '<meta foo-type="#{name}" content="#{content}"'
94
+ add_meta_format(:foo, format)
95
+ assert self.instance_variable_get("@manage_meta_format_hash").key?(:foo),
96
+ "add_meta_format adds key to format_hash using symbol"
97
+ assert self.instance_variable_get("@manage_meta_format_hash")[:foo] == format,
98
+ "add_meta_format adds format properly"
99
+ add_meta_format('bar', format)
100
+ assert self.instance_variable_get("@manage_meta_format_hash").key?(:bar),
101
+ "add_meta_format adds key to format_hash using string"
102
+ assert self.instance_variable_get("@manage_meta_format_hash")[:bar] == format,
103
+ "add_meta_format adds format properly"
104
+ end
105
+
106
+ # test 'render_meta' do
107
+ def test_render_meta_renders_meta
108
+ assert_match /name="robots"/, render_meta, "render_meta contains robots meta tag"
109
+ assert_match /name="generator"/, render_meta, "render_meta contains generator meta tag" \
110
+ if defined? Rails
111
+ add_meta :foo, 'a value'
112
+ assert_match /name="foo"/, render_meta, "render_meta contains 'foo' meta tag"
113
+ assert_match /content="a value"/, render_meta, "render_meta tag for foo has content 'a value'"
114
+ end
115
+
116
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: manage_meta
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.4
6
+ platform: ruby
7
+ authors:
8
+ - Mike Howard
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-04-13 00:00:00 -06:00
14
+ default_executable:
15
+ dependencies: []
16
+
17
+ description: Provides (semi-)intellegent management of meta tags for Rails 3
18
+ email: mike@clove.com
19
+ executables: []
20
+
21
+ extensions: []
22
+
23
+ extra_rdoc_files: []
24
+
25
+ files:
26
+ - lib/manage_meta/manage_meta.rb
27
+ - lib/manage_meta.rb
28
+ - test/manage_meta_test.rb
29
+ - MIT-LICENSE
30
+ - Rakefile
31
+ - README.markdown
32
+ has_rdoc: true
33
+ homepage: http://github.com/mikehoward/manage_meta
34
+ licenses: []
35
+
36
+ post_install_message:
37
+ rdoc_options: []
38
+
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ none: false
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: "0"
53
+ requirements: []
54
+
55
+ rubyforge_project:
56
+ rubygems_version: 1.6.2
57
+ signing_key:
58
+ specification_version: 3
59
+ summary: ManageMeta - Yet Another Meta Tag manager for Rails 3
60
+ test_files: []
61
+