navigasmic 0.5.6 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +7 -1
- data/lib/generators/navigasmic/install/POST_INSTALL +6 -0
- data/lib/generators/navigasmic/install/install_generator.rb +17 -0
- data/lib/generators/navigasmic/install/templates/initializer.rb +145 -0
- data/lib/navigasmic.rb +5 -146
- data/lib/navigasmic/builders/crumb_builder.rb +20 -0
- data/lib/navigasmic/builders/list_builder.rb +90 -0
- data/lib/navigasmic/builders/map_builder.rb +77 -0
- data/lib/navigasmic/core/builders.rb +109 -0
- data/lib/navigasmic/core/configuration.rb +38 -0
- data/lib/navigasmic/core/item.rb +66 -0
- data/lib/navigasmic/rails.rb +2 -0
- data/lib/navigasmic/rails/engine.rb +9 -0
- data/lib/navigasmic/rails/view_helpers.rb +18 -0
- data/lib/navigasmic/version.rb +3 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/controllers/application_controller.rb +13 -0
- data/spec/dummy/app/controllers/blog/links_controller.rb +7 -0
- data/spec/dummy/app/controllers/blog/posts_controller.rb +7 -0
- data/spec/dummy/app/views/application/welcome.html.erb +4 -0
- data/spec/dummy/app/views/application/welcome.xml.builder +2 -0
- data/spec/dummy/app/views/blog/links/index.html +4 -0
- data/spec/dummy/app/views/blog/links/show.html +4 -0
- data/spec/dummy/app/views/blog/posts/index.html +4 -0
- data/spec/dummy/app/views/blog/posts/show.html +4 -0
- data/spec/dummy/app/views/layouts/_navigation.html.erb +73 -0
- data/spec/dummy/app/views/layouts/application.html.erb +40 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +57 -0
- data/spec/dummy/config/boot.rb +9 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/evergreen.rb +47 -0
- data/spec/dummy/config/initializers/additional_navigasmic.rb +14 -0
- data/spec/dummy/config/initializers/navigasmic.rb +145 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +68 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/public/bootstrap.min.css +9 -0
- data/spec/dummy/public/bootstrap.min.js +6 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/public/jquery.min.js +2 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/spec_helper.rb +39 -0
- metadata +139 -63
- data/.document +0 -5
- data/README.textile +0 -276
- data/Rakefile +0 -57
- data/VERSION +0 -1
- data/lib/builders/html_builder.rb +0 -69
- data/lib/builders/xml_builder.rb +0 -51
- data/navigasmic.gemspec +0 -49
- data/test/navigasmic_test.rb +0 -7
- data/test/test_helper.rb +0 -10
data/LICENSE
CHANGED
@@ -1,4 +1,10 @@
|
|
1
|
-
|
1
|
+
Navigasmic is a semantic way to build beautifully simple navigation
|
2
|
+
structures in Rails.
|
3
|
+
|
4
|
+
Documentation and other useful information can be found at
|
5
|
+
https://github.com/jejacks0n/navigasmic
|
6
|
+
|
7
|
+
Copyright (c) 2011 Jeremy Jackson
|
2
8
|
|
3
9
|
Permission is hereby granted, free of charge, to any person obtaining
|
4
10
|
a copy of this software and associated documentation files (the
|
@@ -0,0 +1,6 @@
|
|
1
|
+
+============================================================================+
|
2
|
+
Congratulations! Navigasmic was successfully installed. Documentation and more
|
3
|
+
can be found at: https://github.com/jejacks0n/navigasmic
|
4
|
+
|
5
|
+
You should start defining some navigation in config/initializers/navigasmic.rb
|
6
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Navigasmic
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
source_root File.expand_path('../', __FILE__)
|
5
|
+
|
6
|
+
desc "Installs the Navigasmic initializer into your application."
|
7
|
+
|
8
|
+
def copy_initializer
|
9
|
+
copy_file 'templates/initializer.rb', 'config/initializers/navigasmic.rb'
|
10
|
+
end
|
11
|
+
|
12
|
+
def display_readme
|
13
|
+
readme 'POST_INSTALL' if behavior == :invoke
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
Navigasmic.setup do |config|
|
2
|
+
|
3
|
+
# Defining Navigation Structures:
|
4
|
+
#
|
5
|
+
# You can begin by defining your navigation structures here. You can also define them directly in the view if you'd
|
6
|
+
# like, but it's recommended to eventually move them here to clean help up your views. You can read about Navigasmic
|
7
|
+
# at https://github.com/jejacks0n/navigasmic
|
8
|
+
#
|
9
|
+
# When you're defining navigation here, it's basically the same as if you were doing it in the view but the scope is
|
10
|
+
# different. It's important to understand that -- and use procs where you want things to execute in the view scope.
|
11
|
+
#
|
12
|
+
# Once you've defined some navigation structures and configured your builders you can render navigation in your views
|
13
|
+
# using the `semantic_navigation` view helper. You can also use the same syntax to define your navigation structures
|
14
|
+
# in your views, and eventually move them here (it's handy to prototype navigation/css by putting them in the views
|
15
|
+
# first).
|
16
|
+
#
|
17
|
+
# <%= semantic_navigation :primary %>
|
18
|
+
#
|
19
|
+
# You can optionally provided a :builder and :config option to the semantic_navigation view helper.
|
20
|
+
#
|
21
|
+
# <%= semantic_navigation :primary, config: :blockquote %>
|
22
|
+
# <%= semantic_navigation :primary, builder: Navigasmic::Builder::MapBuilder %>
|
23
|
+
#
|
24
|
+
# When defining navigation in your views just pass it a block (the same as here basically).
|
25
|
+
#
|
26
|
+
# <%= semantic_navigation :primary do |n| %>
|
27
|
+
# <% n.item 'About Me' %>
|
28
|
+
# <% end %>
|
29
|
+
#
|
30
|
+
# Here's a basic example:
|
31
|
+
config.semantic_navigation :primary do |n|
|
32
|
+
|
33
|
+
n.item 'Home', '/'
|
34
|
+
|
35
|
+
# Groups and Items:
|
36
|
+
#
|
37
|
+
# You can create a structure using `group`, and `item`. You can nest items inside groups or items. In the
|
38
|
+
# following example, the "Articles" item will always highlight on the blog/posts controller, and the nested article
|
39
|
+
# items will only highlight when on those specific pages. The "Links" item will be disabled unless the user is
|
40
|
+
# logged in.
|
41
|
+
#
|
42
|
+
#n.group 'Blog' do
|
43
|
+
# n.item 'Articles', controller: '/blog/posts' do
|
44
|
+
# n.item 'First Article', '/blog/posts/1'
|
45
|
+
# n.item 'Second Article', '/blog/posts/2', map: {changefreq: 'weekly'}
|
46
|
+
# end
|
47
|
+
# n.item 'Links', controller: '/blog/links', disabled_if: proc{ !logged_in? }
|
48
|
+
#end
|
49
|
+
#
|
50
|
+
# You can hide specific specific items or groups. Here we specify that the "About" section of navigation should
|
51
|
+
# only be displayed if the user is logged in.
|
52
|
+
#
|
53
|
+
#n.group 'About', hidden_unless: proc{ logged_in? } do
|
54
|
+
# n.item 'About Me', class: 'featured', link_html: {class: 'about-me'}
|
55
|
+
#end
|
56
|
+
#
|
57
|
+
# Scoping:
|
58
|
+
#
|
59
|
+
# Scoping is different than in the view here, so we've provided some nice things for you to get around that. In
|
60
|
+
# the above example we just provide '/' as what the home page is, but that may not be correct. You can also access
|
61
|
+
# the path helpers, using a proc, or by proxying them through the navigation object. Any method called on the
|
62
|
+
# navigation scope will be called within the view scope.
|
63
|
+
#
|
64
|
+
#n.item 'Home', proc{ root_path }
|
65
|
+
#n.item 'Home', n.root_path
|
66
|
+
#
|
67
|
+
# This proxy behavior can be used for I18n as well.
|
68
|
+
#
|
69
|
+
#n.item n.t('hello'), '/'
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
# Setting the Default Builder:
|
75
|
+
#
|
76
|
+
# By default the Navigasmic::Builder::ListBuilder is used unless otherwise specified.
|
77
|
+
#
|
78
|
+
# You can change this here:
|
79
|
+
#config.default_builder = MyCustomBuilder
|
80
|
+
|
81
|
+
|
82
|
+
# Configuring Builders:
|
83
|
+
#
|
84
|
+
# You can change various builder options here by specifying the builder you want to configure and the options you
|
85
|
+
# want to change.
|
86
|
+
#
|
87
|
+
# Changing the default ListBuilder options:
|
88
|
+
config.builder Navigasmic::Builder::ListBuilder do |builder|
|
89
|
+
builder.wrapper_class = 'semantic-navigation'
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
# Naming Builder Configurations:
|
94
|
+
#
|
95
|
+
# If you want to define a named configuration for a builder, just provide a hash with the name, and the builder to
|
96
|
+
# configure. The named configurations can then be used during rendering by specifying a `:config => :bootstrap`
|
97
|
+
# option to the `semantic_navigation` view helper.
|
98
|
+
#
|
99
|
+
# A Twitter Bootstrap configuration:
|
100
|
+
#
|
101
|
+
# Example usage:
|
102
|
+
#
|
103
|
+
# <%= semantic_navigation :primary, config: :bootstrap, class: 'nav-pills' %>
|
104
|
+
#
|
105
|
+
# Or to create a full navigation bar using twitter bootstrap you could use the following in your view:
|
106
|
+
# <div class="navbar">
|
107
|
+
# <div class="navbar-inner">
|
108
|
+
# <a class="brand" href="/">Title</a>
|
109
|
+
# <%= semantic_navigation :primary, config: :bootstrap %>
|
110
|
+
# </div>
|
111
|
+
# </div>
|
112
|
+
config.builder bootstrap: Navigasmic::Builder::ListBuilder do |builder|
|
113
|
+
|
114
|
+
# Set the nav and nav-pills css (you can also use 'nav nav-tabs') -- or remove them if you're using this inside a
|
115
|
+
# navbar.
|
116
|
+
builder.wrapper_class = 'nav nav-pills'
|
117
|
+
|
118
|
+
# Set the classed for items that have nested items, and that are nested items.
|
119
|
+
builder.has_nested_class = 'dropdown'
|
120
|
+
builder.is_nested_class = 'dropdown-menu'
|
121
|
+
|
122
|
+
# For dropdowns to work you'll need to include the bootstrap dropdown js
|
123
|
+
# For groups, we adjust the markup so they'll be clickable and be picked up by the javascript.
|
124
|
+
builder.label_generator = proc do |label, has_link, has_nested|
|
125
|
+
if !has_nested || has_link
|
126
|
+
"<span>#{label}</span>"
|
127
|
+
else
|
128
|
+
link_to("#{label}<b class='caret'></b>".html_safe, '#', class: 'dropdown-toggle', data: {toggle: 'dropdown'})
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# For items, we adjust the links so they're '#', and do the same as for groups. This allows us to use more complex
|
133
|
+
# highlighting rules for dropdowns.
|
134
|
+
builder.link_generator = proc do |label, link, options, has_nested|
|
135
|
+
if has_nested
|
136
|
+
link = '#'
|
137
|
+
label << "<b class='caret'></b>"
|
138
|
+
options.merge!(class: 'dropdown-toggle', data: {toggle: 'dropdown'})
|
139
|
+
end
|
140
|
+
link_to(label, link, options)
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
data/lib/navigasmic.rb
CHANGED
@@ -1,147 +1,6 @@
|
|
1
|
-
|
2
|
-
require '
|
3
|
-
require 'builders/xml_builder'
|
1
|
+
require 'navigasmic/version'
|
2
|
+
require 'navigasmic/rails'
|
4
3
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
#
|
9
|
-
# Example Usage:
|
10
|
-
#
|
11
|
-
# <% semantic_navigation :primary, :html => {:class => 'primary'} do |n| %>
|
12
|
-
# <%= n.item 'Blog Posts', :link => {:controller => 'posts'} %>
|
13
|
-
# <% end %>
|
14
|
-
#
|
15
|
-
# <% semantic_navigation :primary, :builder => MyCustomBuilder do |n| %>
|
16
|
-
# <%= n.group 'My Thoughts' do %>
|
17
|
-
# <%= n.item 'Blog Posts', :link => {:controller => 'posts'} %>
|
18
|
-
# <% end %>
|
19
|
-
# <% end %>
|
20
|
-
#
|
21
|
-
# <% semantic_navigation :primary do |n| %>
|
22
|
-
# <%= n.group 'My Thoughts' do %>
|
23
|
-
# <%= n.item 'Blog Posts', :link => {:controller => 'posts'} do %>
|
24
|
-
# <ul>
|
25
|
-
# <%= n.item 'Recent Posts', :link => {:controller => 'posts', :action => 'recent'} %>
|
26
|
-
# </ul>
|
27
|
-
# <% end %>
|
28
|
-
# <% end %>
|
29
|
-
# <% end %>
|
30
|
-
module SemanticNavigationHelper
|
31
|
-
|
32
|
-
@@builder = ::Navigasmic::HtmlNavigationBuilder
|
33
|
-
mattr_accessor :builder
|
34
|
-
|
35
|
-
def semantic_navigation(name, *args, &proc)
|
36
|
-
raise ArgumentError, "Missing block" unless block_given?
|
37
|
-
|
38
|
-
options = args.extract_options!
|
39
|
-
|
40
|
-
options[:html] ||= {}
|
41
|
-
options[:html][:class] = add_html_class(options[:html][:class], 'semantic-navigation')
|
42
|
-
options[:html][:id] ||= name.to_s.underscore unless options[:html].has_key?(:id)
|
43
|
-
|
44
|
-
builder = options.delete(:builder) || @@builder
|
45
|
-
builder.new(self, name, options, &proc)
|
46
|
-
end
|
47
|
-
|
48
|
-
def add_html_class(classnames, classname)
|
49
|
-
out = (classnames.is_a?(String) ? classnames.split(' ') : []) << classname
|
50
|
-
out.join(' ')
|
51
|
-
end
|
52
|
-
|
53
|
-
end
|
54
|
-
|
55
|
-
#
|
56
|
-
#
|
57
|
-
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
class NavigationItem
|
61
|
-
|
62
|
-
attr_accessor :label, :link
|
63
|
-
|
64
|
-
def initialize(label, options = {}, template = nil)
|
65
|
-
@label = label
|
66
|
-
|
67
|
-
if options[:link]
|
68
|
-
@link = options[:link]
|
69
|
-
elsif template.present?
|
70
|
-
method = "#{label.to_s.underscore.gsub(/\s/, '_')}_path"
|
71
|
-
@link = template.send(method) if template.respond_to? method
|
72
|
-
end
|
73
|
-
@link ||= {}
|
74
|
-
|
75
|
-
@disabled_conditions = options[:disabled_if] || proc { false }
|
76
|
-
@visible = options[:hidden_unless].nil? ? true : options[:hidden_unless].is_a?(Proc) ? template.instance_eval(&options[:hidden_unless]) : options[:hidden_unless]
|
77
|
-
|
78
|
-
options[:highlights_on] = [options[:highlights_on]] if options[:highlights_on].kind_of?(Hash) || options[:highlights_on].kind_of?(String)
|
79
|
-
@highlights_on = options[:highlights_on] || []
|
80
|
-
|
81
|
-
if link?
|
82
|
-
if @link.is_a?(Proc)
|
83
|
-
@highlights_on << template.instance_eval(&@link)
|
84
|
-
else
|
85
|
-
@highlights_on << @link if link?
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def link?
|
91
|
-
@link && !@link.blank?
|
92
|
-
end
|
93
|
-
|
94
|
-
def disabled?
|
95
|
-
@disabled_conditions.call
|
96
|
-
end
|
97
|
-
|
98
|
-
def hidden?
|
99
|
-
!@visible
|
100
|
-
end
|
101
|
-
|
102
|
-
def highlighted?(path, params = {}, template = nil)
|
103
|
-
params = clean_unwanted_keys(params)
|
104
|
-
result = false
|
105
|
-
|
106
|
-
@highlights_on.each do |highlight|
|
107
|
-
highlighted = true
|
108
|
-
|
109
|
-
case highlight
|
110
|
-
when String
|
111
|
-
highlighted &= path == highlight
|
112
|
-
when Proc
|
113
|
-
h = template.instance_eval(&highlight)
|
114
|
-
raise 'proc highlighting rules must evaluate to TrueClass or FalseClass' unless (h.is_a?(TrueClass) || h.is_a?(FalseClass))
|
115
|
-
highlighted &= h
|
116
|
-
when Regexp
|
117
|
-
highlighted &= path.match(highlight)
|
118
|
-
when Hash
|
119
|
-
h = clean_unwanted_keys(highlight)
|
120
|
-
h.each_key do |key|
|
121
|
-
h_key = h[key].to_s.dup
|
122
|
-
h_key.gsub!(/^\//, '') if key == :controller
|
123
|
-
highlighted &= h_key == params[key].to_s
|
124
|
-
end
|
125
|
-
else
|
126
|
-
raise 'highlighting rules should be a String, Proc, Regexp or a Hash'
|
127
|
-
end
|
128
|
-
|
129
|
-
result |= highlighted
|
130
|
-
end
|
131
|
-
|
132
|
-
return result
|
133
|
-
end
|
134
|
-
|
135
|
-
private
|
136
|
-
|
137
|
-
# removes unwanted keys from a Hash and returns a new hash
|
138
|
-
def clean_unwanted_keys(hash)
|
139
|
-
ignored_keys = [:only_path, :use_route]
|
140
|
-
hash.dup.delete_if { |key, value| ignored_keys.include?(key) }
|
141
|
-
end
|
142
|
-
|
143
|
-
end
|
144
|
-
|
145
|
-
end
|
146
|
-
|
147
|
-
ActionController::Base.helper Navigasmic::SemanticNavigationHelper
|
4
|
+
require 'navigasmic/core/builders'
|
5
|
+
require 'navigasmic/core/configuration'
|
6
|
+
require 'navigasmic/core/item'
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Navigasmic::Builder
|
2
|
+
class CrumbBuilder < Base
|
3
|
+
class Configuration < Base::Configuration
|
4
|
+
end
|
5
|
+
|
6
|
+
def initialize(context, name, options, &block)
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
def render
|
11
|
+
end
|
12
|
+
|
13
|
+
def group(label = nil, options = {}, &block)
|
14
|
+
end
|
15
|
+
|
16
|
+
def item(label, *args, &block)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Navigasmic::Builder
|
2
|
+
class ListBuilder < Base
|
3
|
+
class Configuration < Base::Configuration
|
4
|
+
|
5
|
+
attr_accessor :wrapper_class, :has_nested_class, :is_nested_class, :disabled_class, :highlighted_class
|
6
|
+
attr_accessor :wrapper_tag, :group_tag, :item_tag
|
7
|
+
attr_accessor :link_generator, :label_generator
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
# which keys (for other builder) should be removed from options
|
11
|
+
@excluded_keys = [:map]
|
12
|
+
|
13
|
+
# tag configurations
|
14
|
+
@wrapper_tag = :ul
|
15
|
+
@group_tag = :ul
|
16
|
+
@item_tag = :li
|
17
|
+
|
18
|
+
# class configurations
|
19
|
+
@wrapper_class = 'semantic-navigation'
|
20
|
+
@has_nested_class = 'has-nested'
|
21
|
+
@is_nested_class = 'is-nested'
|
22
|
+
@disabled_class = 'disabled'
|
23
|
+
@highlighted_class = 'active'
|
24
|
+
|
25
|
+
# generator callbacks
|
26
|
+
@link_generator = proc{ |label, link, options, is_nested| link_to(label, link, options.delete(:link_html)) }
|
27
|
+
@label_generator = proc{ |label, is_linked, is_nested| "<span>#{label}</span>" }
|
28
|
+
|
29
|
+
super
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(context, name, options, &block)
|
34
|
+
super
|
35
|
+
@options[:id] ||= name.to_s.underscore unless @options.has_key?(:id)
|
36
|
+
@options[:class] = merge_classes!(@options, @config.wrapper_class)
|
37
|
+
end
|
38
|
+
|
39
|
+
def render
|
40
|
+
content_tag(@config.wrapper_tag, capture(&@definition), @options)
|
41
|
+
end
|
42
|
+
|
43
|
+
def group(label = nil, options = {}, &block)
|
44
|
+
raise ArgumentError, "Missing block for group" unless block_given?
|
45
|
+
return '' unless visible?(options)
|
46
|
+
|
47
|
+
concat(structure_for(label, false, options, &block))
|
48
|
+
end
|
49
|
+
|
50
|
+
def item(label, *args, &block)
|
51
|
+
options = args.extract_options!
|
52
|
+
options = flatten_and_eval_options(options)
|
53
|
+
return '' unless visible?(options)
|
54
|
+
|
55
|
+
item = Navigasmic::Item.new(self, label, extract_and_determine_link(label, options, *args), options)
|
56
|
+
|
57
|
+
merge_classes!(options, @config.disabled_class) if item.disabled?
|
58
|
+
merge_classes!(options, @config.highlighted_class) if item.highlights_on?(@context.request.path, @context.params)
|
59
|
+
|
60
|
+
concat(structure_for(label, item.link? ? item.link : false, options, &block))
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def structure_for(label, link = false, options = {}, &block)
|
66
|
+
label = label_for(label, link, block_given?, options)
|
67
|
+
|
68
|
+
content = ''
|
69
|
+
if block_given?
|
70
|
+
merge_classes!(options, @config.has_nested_class)
|
71
|
+
content = content_tag(@config.group_tag, capture(&block), {class: @config.is_nested_class})
|
72
|
+
end
|
73
|
+
|
74
|
+
content_tag(@config.item_tag, "#{label}#{content}".html_safe, options)
|
75
|
+
end
|
76
|
+
|
77
|
+
def label_for(label, link, is_nested = false, options = {})
|
78
|
+
if label.present?
|
79
|
+
label = @context.instance_exec(label, !!link, is_nested, &@config.label_generator).html_safe
|
80
|
+
end
|
81
|
+
label = @context.instance_exec(label, link, options.delete(:link_html) || {}, is_nested, &@config.link_generator).html_safe if link
|
82
|
+
label
|
83
|
+
end
|
84
|
+
|
85
|
+
def merge_classes!(hash, classname)
|
86
|
+
hash[:class] = (hash[:class] ? "#{hash[:class]} " : '') << classname
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|