lib/simple_navigation.rb in simple-navigation-2.7.3 vs lib/simple_navigation.rb in simple-navigation-3.0.0.beta1
- old
+ new
@@ -1,124 +1,123 @@
-# Load all source files (if this is not done explicitly some naming conflicts may occur if rails app has classes with the same name)
-require 'simple_navigation/configuration'
-require 'simple_navigation/helpers'
-require 'simple_navigation/controller_methods'
-require 'simple_navigation/item_adapter'
-require 'simple_navigation/item'
-require 'simple_navigation/item_container'
-require 'simple_navigation/items_provider'
-require 'simple_navigation/renderer/base'
-require 'simple_navigation/renderer/list'
-require 'simple_navigation/renderer/links'
-require 'simple_navigation/renderer/breadcrumbs'
-require 'simple_navigation/initializer'
-require 'simple_navigation/railtie' if Rails::VERSION::MAJOR == 3
+# cherry picking active_support stuff
+require 'active_support/core_ext/array'
+require 'active_support/core_ext/hash'
+require 'active_support/core_ext/module/attribute_accessors'
+require 'simple_navigation/core'
+require 'simple_navigation/rendering'
+require 'simple_navigation/adapters'
+
+require 'forwardable'
+
# A plugin for generating a simple navigation. See README for resources on usage instructions.
module SimpleNavigation
+
+ mattr_accessor :adapter_class, :adapter, :config_files, :config_file_paths, :default_renderer, :registered_renderers, :root, :environment
- mattr_accessor :config_files, :config_file_paths, :default_renderer, :controller, :template, :explicit_current_navigation, :rails_env, :rails_root, :registered_renderers
-
+ # Cache for loaded config files
self.config_files = {}
+
+ # Allows for multiple config_file_paths. Needed if a plugin itself uses simple-navigation and therefore has its own config file
self.config_file_paths = []
+
+ # Maps renderer keys to classes. The keys serve as shortcut in the render_navigation calls (:renderer => :list)
self.registered_renderers = {
:list => SimpleNavigation::Renderer::List,
:links => SimpleNavigation::Renderer::Links,
:breadcrumbs => SimpleNavigation::Renderer::Breadcrumbs
}
-
class << self
+ extend Forwardable
+
+ def_delegators :adapter, :request, :request_uri, :request_path, :context_for_eval, :current_page?
+ def_delegators :adapter_class, :register
- # Sets the config file path and installs the ControllerMethods in ActionController::Base.
- def init_rails
- SimpleNavigation.config_file_paths << SimpleNavigation.default_config_file_path
- ActionController::Base.send(:include, SimpleNavigation::ControllerMethods)
+ # Sets the root path and current environment as specified. Also sets the default config_file_path.
+ def set_env(root, environment)
+ self.root = root
+ self.environment = environment
+ self.config_file_paths << SimpleNavigation.default_config_file_path
end
+
+ # Returns the current framework in which the plugin is running.
+ def framework
+ return :rails if defined?(Rails)
+ return :padrino if defined?(Padrino)
+ return :sinatra if defined?(Sinatra)
+ raise 'simple_navigation currently only works for Rails, Sinatra and Padrino apps'
+ end
+
+ # Loads the adapter for the current framework
+ def load_adapter
+ self.adapter_class = case framework
+ when :rails
+ SimpleNavigation::Adapters::Rails
+ when :sinatra
+ SimpleNavigation::Adapters::Sinatra
+ when :padrino
+ SimpleNavigation::Adapters::Padrino
+ end
+ end
+
+ # Creates a new adapter instance based on the context in which render_navigation has been called.
+ def init_adapter_from(context)
+ self.adapter = self.adapter_class.new(context)
+ end
def default_config_file_path
- File.join(SimpleNavigation.rails_root, 'config')
+ File.join(SimpleNavigation.root, 'config')
end
-
+
# Returns true if the config_file for specified context does exist.
def config_file?(navigation_context = :default)
!!config_file(navigation_context)
end
-
- # Returns the config file for the given navigation context or nil if no matching config file can be found.
- # If multiple config_paths are set, it returns the first matching file.
- #
+
+ # Returns the path to the config file for the given navigation context or nil if no matching config file can be found.
+ # If multiple config_paths are set, it returns the first matching path.
def config_file(navigation_context = :default)
config_file_paths.collect { |path| File.join(path, config_file_name(navigation_context)) }.detect {|full_path| File.exists?(full_path)}
end
-
+
# Returns the name of the config file for the given navigation_context
def config_file_name(navigation_context = :default)
prefix = navigation_context == :default ? '' : "#{navigation_context.to_s.underscore}_"
"#{prefix}navigation.rb"
end
-
- # Returns a nice sentence including all config_paths
- def config_file_paths_sentence
- self.config_file_paths.to_sentence(
- :last_word_connector => ', or ',
- :two_words_connector => ' or '
- )
- end
- # Sets the config_file_path
+ # Resets the list of config_file_paths to the specified path
def config_file_path=(path)
self.config_file_paths = [path]
end
-
+
# Reads the config_file for the specified navigation_context and stores it for later evaluation.
def load_config(navigation_context = :default)
- raise "Config file for #{navigation_context} context not found in #{config_file_paths_sentence}!" unless config_file?(navigation_context)
- if SimpleNavigation.rails_env == 'production'
+ raise "Config file '#{config_file_name(navigation_context)}' not found in path(s) #{config_file_paths.join(', ')}!" unless config_file?(navigation_context)
+ if self.environment == 'production'
self.config_files[navigation_context] ||= IO.read(config_file(navigation_context))
else
self.config_files[navigation_context] = IO.read(config_file(navigation_context))
end
end
- def set_template_from(context)
- SimpleNavigation.controller = extract_controller_from context
- SimpleNavigation.template = SimpleNavigation.controller.instance_variable_get(:@template) || (SimpleNavigation.controller.respond_to?(:view_context) ? SimpleNavigation.controller.view_context : nil)
- end
-
- # Returns the context in which the config file should be evaluated.
- # This is preferably the template, otherwise te controller
- def context_for_eval
- raise 'no context set for evaluation the config file' unless SimpleNavigation.template || SimpleNavigation.controller
- SimpleNavigation.template || SimpleNavigation.controller
- end
-
# Returns the singleton instance of the SimpleNavigation::Configuration
- def config
+ def config
SimpleNavigation::Configuration.instance
end
-
+
# Returns the ItemContainer that contains the items for the primary navigation
def primary_navigation
config.primary_navigation
end
- def explicit_navigation_args
- self.controller.instance_variable_get(:"@sn_current_navigation_args")
- end
-
- # Reads the current navigation for the specified level from the controller.
- # Returns nil if there is no current navigation set for level.
- def current_navigation_for(level)
- self.controller.instance_variable_get(:"@sn_current_navigation_#{level}")
- end
-
# Returns the active item container for the specified level. Valid levels are
# * :all - in this case the primary_navigation is returned.
# * a specific level - the active item_container for the specified level will be returned
# * a range of levels - the active item_container for the range's minimum will be returned
- #
+ #
# Returns nil if there is no active item_container for the specified level.
def active_item_container_for(level)
case level
when :all
self.primary_navigation
@@ -128,106 +127,25 @@
self.primary_navigation.active_item_container_for(level.min)
else
raise ArgumentError, "Invalid navigation level: #{level}"
end
end
-
- # If any navigation has been explicitely set in the controller this method evaluates the specified args set in the controller and sets
- # the correct instance variable in the controller.
- def handle_explicit_navigation
- if SimpleNavigation.explicit_navigation_args
- begin
- level, navigation = parse_explicit_navigation_args
- self.controller.instance_variable_set(:"@sn_current_navigation_#{level}", navigation)
- rescue
- #we do nothing here
- #TODO: check if this is the right way to handle wrong explicit navigation
- end
- end
- end
-
- # Extracts a controller from the context.
- def extract_controller_from(context)
- if context.respond_to? :controller
- context.controller
- else
- context
- end
- end
-
+
# Registers a renderer.
#
# === Example
- # To register your own renderer:
+ # To register your own renderer:
#
# SimpleNavigation.register_renderer :my_renderer => My::RendererClass
- #
+ #
# Then in the view you can call:
#
# render_navigation(:renderer => :my_renderer)
- #
def register_renderer(renderer_hash)
self.registered_renderers.merge!(renderer_hash)
- end
+ end
- # Returns the current request.
- #
- def request
- SimpleNavigation.template.request if SimpleNavigation.template
- end
-
- # Returns the current request's URI.
- #
- def request_uri
- return '' unless SimpleNavigation.request
- return SimpleNavigation.request.fullpath if SimpleNavigation.request.respond_to?(:fullpath)
- SimpleNavigation.request.request_uri
- end
-
- private
-
-
- # TODO: refactor this ugly thing to make it nice and short
- def parse_explicit_navigation_args
- args = SimpleNavigation.explicit_navigation_args
- args = [Hash.new] if args.empty?
- if args.first.kind_of? Hash
- options = args.first
- else # args is a list of current navigation for several levels
- options = {}
- if args.size == 1 #only an navi-key has been specified, try to find out level
- level = SimpleNavigation.primary_navigation.level_for_item(args.first)
- options[:"level_#{level}"] = args.first if level
- else
- args.each_with_index {|arg, i| options[:"level_#{i + 1}"] = arg}
- end
- end
- #only the deepest level is relevant
- level = options.inject(0) do |max, kv|
- kv.first.to_s =~ /level_(\d)/
- max = $1.to_i if $1.to_i > max
- max
- end
- raise ArgumentError, "Invalid level specified or item key not found" if level == 0
- [level, options[:"level_#{level}"]]
- end
-
end
end
-# TODOs for the next releases:
-# 1) add ability to specify explicit highlighting in the config-file itself (directly with the item)
-# - item.highlight_on :controller => 'users', :action => 'show' ...^
-# --> with that we can get rid of the controller_methods...
-#
-# 2) ability to turn off autohighlighting for a single item...
-#
-# 3) add JoinRenderer (HorizontalRenderer?) (wich does not render a list, but just the items joined with a specified char (e.g. | ))
-#
-# 4) Enhance SampleProject (more examples)
-#
-# 5) Make SampleProject public
-#
-# - allow :function navigation item to specify function
-# - allow specification of link-options in item (currently options are passed to li-element)
-# - render_navigation: do not rescue from config-file not found error if no items are passed in directly
+SimpleNavigation.load_adapter