Class: Nav

Inherits:
Array
  • Object
show all
Defined in:
lib/rails_nav.rb

Defined Under Namespace

Classes: Link, Slug, Template

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name = :main, &block) ⇒ Nav

Returns a new instance of Nav.



92
93
94
95
96
97
98
99
# File 'lib/rails_nav.rb', line 92

def initialize(name = :main, &block)
  @name = name.to_s
  @block = block
  @already_computed_active = false
  @controller = nil
  @strategy = :call
  @active = nil
end

Instance Attribute Details

#activeObject

Returns the value of attribute active.



90
91
92
# File 'lib/rails_nav.rb', line 90

def active
  @active
end

#blockObject

Returns the value of attribute block.



86
87
88
# File 'lib/rails_nav.rb', line 86

def block
  @block
end

#controllerObject

Returns the value of attribute controller.



87
88
89
# File 'lib/rails_nav.rb', line 87

def controller
  @controller
end

#nameObject

Returns the value of attribute name.



85
86
87
# File 'lib/rails_nav.rb', line 85

def name
  @name
end

#strategyObject

Returns the value of attribute strategy.



88
89
90
# File 'lib/rails_nav.rb', line 88

def strategy
  @strategy
end

#weightsObject

Returns the value of attribute weights.



89
90
91
# File 'lib/rails_nav.rb', line 89

def weights
  @weights
end

Class Method Details

.build(*args, &block) ⇒ Object

for use when the controller instance is available now

Nav.build do |nav|

nav.link 'Home', root_path

end



69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/rails_nav.rb', line 69

def Nav.build(*args, &block)
  if defined?(::ActionController::Base)
    controller = args.grep(::ActionController::Base).first
    args.delete(controller)
  end

  new(*args, &block).tap do |nav|
    nav.strategy = :call
    nav.controller = controller || Current.controller || Current.mock_controller
    nav.build!
    nav.compute_active!
  end
end

.dependenciesObject



13
14
15
16
17
18
19
# File 'lib/rails_nav.rb', line 13

def Nav.dependencies
  {
    'rails_current' => [ 'rails_current' , ' >= 1.6'   ],
    'rails_helper'  => [ 'rails_helper'  , ' >= 1.2'   ],
    'map'           => [ 'map'           , ' >= 6.5'   ],
  }
end

.descriptionObject



21
22
23
# File 'lib/rails_nav.rb', line 21

def Nav.description
  'declarative navigation for rails applications'
end

.extend_action_controller!Object

factored out mixin for controllers/views



381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
# File 'lib/rails_nav.rb', line 381

def Nav.extend_action_controller!
  if defined?(::ActionController::Base)
    ::ActionController::Base.module_eval do
      class << self
        def nav_for(*args, &block)
          options = args.extract_options!.to_options!
          name = args.first || options[:name] || :main
          which_nav = [:nav, name].join('_')
          define_method(which_nav){ Nav.for(name, &block) }
          protected(which_nav)
        end
        alias_method(:nav, :nav_for)
      end

      def nav_for(*args, &block)
        options = args.extract_options!.to_options!
        name = args.first || options[:name] || :main
        Nav.for(name, &block).for(controller = self)
      end
      alias_method(:nav, :nav_for)

      helper do
        def nav_for(*args, &block)
          options = args.extract_options!.to_options!
          name = args.first || options[:name] || :main
          which_nav = [:nav, name].join('_')
          nav = controller.send(which_nav).for(controller)
        end
        alias_method(:nav, :nav_for)
      end
    end
  end
end

.for(*args, &block) ⇒ Object

for use in a controller

nav_for(:main) do |nav|

  nav.link 'Home', root_path

end


44
45
46
47
48
# File 'lib/rails_nav.rb', line 44

def Nav.for(*args, &block)
  new(*args, &block).tap do |nav|
    nav.strategy = :instance_exec
  end
end

.versionObject



9
10
11
# File 'lib/rails_nav.rb', line 9

def Nav.version()
  '2.8.0'
end

Instance Method Details

#build!Object



106
107
108
# File 'lib/rails_nav.rb', line 106

def build!
  evaluate(@block, nav = self)
end

#compute_activeObject



179
180
181
182
# File 'lib/rails_nav.rb', line 179

def compute_active
  compute_active! unless @already_computed_active
  self
end

#compute_active!Object



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/rails_nav.rb', line 117

def compute_active!
  nav = self

  unless empty?
    weights = []

    each_with_index do |link, index|
      link.controller = @controller
      active = link.compute_active!

      weight =
        begin
          case active
            when nil, false
              -1
            when true
              0
            else
              Integer(active)
          end
        rescue
          -1
        end

      link.weight = weight
      weights[index] = weight
    end

    nav.weights = weights

    each_with_index do |link, index|
      link.active = false
    end

    more_than_one_link =
      size > 1

    equivalently_active =
      weights.uniq.size < 2

    no_clear_winner =
      more_than_one_link && equivalently_active

    active_link =
      if no_clear_winner
        detect{|link| link.default}
      else
        max = weights.max
        longest_matching_link = select{|link| link.weight == max}.sort{|a,b| a.content.size <=> b.content.size}.last
      end

    if active_link
      active_link.active = true
      nav.active = active_link
    end

    @already_computed_active = true
  end

  nav
end

#evaluate(block, *args) ⇒ Object



101
102
103
104
# File 'lib/rails_nav.rb', line 101

def evaluate(block, *args)
  args = args.slice(0 .. (block.arity < 0 ? -1 : block.arity))
  @strategy == :instance_exec ? @controller.instance_exec(*args, &block) : block.call(*args)
end

#for(controller) ⇒ Object

for use in a view

<%= nav_for(:main) %>


54
55
56
57
58
59
# File 'lib/rails_nav.rb', line 54

def for(controller)
  @controller = controller
  build!
  compute_active!
  self
end

#fullpathObject



188
189
190
# File 'lib/rails_nav.rb', line 188

def fullpath
  request.fullpath
end

#html_safe?Boolean

Returns:

  • (Boolean)


236
237
238
# File 'lib/rails_nav.rb', line 236

def html_safe?
  true
end


110
111
112
113
114
115
# File 'lib/rails_nav.rb', line 110

def link(*args, &block)
  nav = self
  link = Link.new(nav, *args, &block)
  push(link)
  link
end

#path_infoObject



192
193
194
# File 'lib/rails_nav.rb', line 192

def path_info
  path_info = fullpath.scan(%r{[^/]+})
end

#requestObject



184
185
186
# File 'lib/rails_nav.rb', line 184

def request
  @controller.send(:request)
end

#templateObject



208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/rails_nav.rb', line 208

def template
  @template ||= Template.new do
    <<-__
      <nav class="nav-<%= name %>">
        <ul>
          <% each do |link| %>
            <li class="<%= link.active ? :active : :inactive %>">
              <a href="<%= link.url %>" class="<%= link.active ? :active : :inactive %>"><%= link.content %></a>
            </li>
          <% end %>
        </ul>
      </nav>
    __
  end
end

#template=(template) ⇒ Object



224
225
226
# File 'lib/rails_nav.rb', line 224

def template=(template)
  @template = Template.new(template.to_s){}
end

#to_htmlObject Also known as: to_s, to_str, html_safe



228
229
230
# File 'lib/rails_nav.rb', line 228

def to_html
  template.render
end