Skip to content

Commit

Permalink
Merge branch 'AlfonsoUceda-nested_routes'
Browse files Browse the repository at this point in the history
  • Loading branch information
jodosha committed May 11, 2015
2 parents 8f756c4 + 5749254 commit e45ced3
Show file tree
Hide file tree
Showing 13 changed files with 1,865 additions and 42 deletions.
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ if !ENV['TRAVIS']
gem 'yard', require: false
end

gem 'lotus-utils', '~> 0.4', require: false, github: 'lotus/utils', branch: '0.4.x'
gem 'lotus-utils', '~> 0.4', require: false, github: 'lotus/utils', branch: 'master'
gem 'simplecov', require: false
gem 'coveralls', require: false
42 changes: 42 additions & 0 deletions lib/lotus/routing/nested.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
module Lotus
module Routing
# Helper class to calculate nested path
#
# @api private
# @since x.x.x
class Nested
# @api private
# @since x.x.x
SLASH = '/'.freeze

# @api private
# @since x.x.x
def initialize(resource_name, resource)
@resource_name = resource_name.to_s.split(SLASH)
@resource = resource
@path = []
end

# @api private
# @since x.x.x
def calculate_nested_path
_calculate(@resource_name.dup, @resource)
end

# @api private
# @since x.x.x
def nested_path
@path.reverse!.pop
@resource_name.zip(@path).flatten.join
end

private

def _calculate(param_wildcard, resource = nil)
return if resource.nil?
@path << resource.wildcard_param(param_wildcard.pop)
_calculate(param_wildcard, resource.parent_resource)
end
end
end
end
56 changes: 49 additions & 7 deletions lib/lotus/routing/resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ module Routing
class Resource
include Utils::ClassAttribute

# @api private
# @since x.x.x
SLASH = '/'.freeze

# Set of default routes
#
# @api private
Expand Down Expand Up @@ -43,30 +47,68 @@ class Resource
class_attribute :collection
self.collection = Resource::CollectionAction

# @api private
# @since x.x.x
attr_reader :parent_resource

# @api private
# @since 0.1.0
def initialize(router, name, options = {}, &blk)
@router = router
@name = name
@options = Options.new(self.class.actions, options.merge(name: @name))
def initialize(router, name, options = {}, parent_resource = nil, &blk)
@router = router
@name = name
@parent_resource = parent_resource
@options = Options.new(self.class.actions, options.merge(name: @name))
generate(&blk)
end

# Allow nested resources inside resource or resources
#
# @since x.x.x
#
# @see Lotus::Router#resources
def resources(name, options = {}, &blk)
_resource(Resources, name, options, &blk)
end

# Allow nested resource inside resource or resources
#
# @since x.x.x
#
# @see Lotus::Router#resource
def resource(name, options = {}, &blk)
_resource(Resource, name, options, &blk)
end

# Return slash, no wildcard param
#
# @api private
# @since x.x.x
def wildcard_param(route_param = nil)
SLASH
end

private

def _resource(klass, name, options, &blk)
merged_options = options.merge(separator: @options[:separator], namespace: @options[:namespace])
nested_name = "#{@name}#{Resource::Action::NESTED_ROUTES_SEPARATOR}#{name}"
klass.new(@router, nested_name, merged_options, self, &blk)
end

def generate(&blk)
instance_eval(&blk) if block_given?

@options.actions.each do |action|
self.class.action.generate(@router, action, @options)
self.class.action.generate(@router, action, @options, self)
end
end

def member(&blk)
self.class.member.new(@router, @options, &blk)
self.class.member.new(@router, @options, self, &blk)
end

def collection(&blk)
self.class.collection.new(@router, @options, &blk)
self.class.collection.new(@router, @options, self, &blk)
end
end
end
Expand Down
43 changes: 37 additions & 6 deletions lib/lotus/routing/resource/action.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require 'lotus/utils/string'
require 'lotus/utils/path_prefix'
require 'lotus/utils/class_attribute'
require 'lotus/routing/nested'

module Lotus
module Routing
Expand All @@ -15,6 +16,12 @@ class Resource
class Action
include Utils::ClassAttribute

# Nested routes separator
#
# @api private
# @since x.x.x
NESTED_ROUTES_SEPARATOR = '/'.freeze

# Ruby namespace where lookup for default subclasses.
#
# @api private
Expand Down Expand Up @@ -45,8 +52,8 @@ class Action
# @api private
#
# @since 0.1.0
def self.generate(router, action, options)
class_for(action).new(router, options)
def self.generate(router, action, options = {}, resource = nil)
class_for(action).new(router, options, resource)
end

# Initialize an action
Expand All @@ -58,8 +65,10 @@ def self.generate(router, action, options)
# @api private
#
# @since 0.1.0
def initialize(router, options, &blk)
@router, @options = router, options
def initialize(router, options = {}, resource = nil, &blk)
@router = router
@options = options
@resource = resource
generate(&blk)
end

Expand Down Expand Up @@ -157,7 +166,7 @@ def path
# @api private
# @since 0.1.0
def rest_path
namespace.join(resource_name)
namespace.join(_nested_rest_path || resource_name.to_s)
end

# The namespaced name of the action within the whole context of the router.
Expand All @@ -179,7 +188,7 @@ def rest_path
# @api private
# @since 0.1.0
def as
namespace.relative_join(resource_name, self.class.named_route_separator).to_sym
namespace.relative_join(_singularized_as, self.class.named_route_separator).to_sym
end

# The name of the RESTful action.
Expand Down Expand Up @@ -237,6 +246,28 @@ def separator
def controller_name
@options[:controller] || resource_name
end

private

# Singularize as (helper route)
#
# @api private
# @since x.x.x
def _singularized_as
resource_name.to_s.split(NESTED_ROUTES_SEPARATOR).map do |name|
Lotus::Utils::String.new(name).singularize
end.join(self.class.named_route_separator)
end

# Create nested rest path
#
# @api private
# @since x.x.x
def _nested_rest_path
nested = Nested.new(resource_name, @resource)
nested.calculate_nested_path
nested.nested_path
end
end

# Collection action
Expand Down
4 changes: 4 additions & 0 deletions lib/lotus/routing/resource/options.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ class Options
# @since 0.1.0
attr_reader :actions

# @api private
# @since x.x.x
attr_reader :options

# Initialize the options for:
# * Lotus::Router#resource
# * Lotus::Router#resources
Expand Down
9 changes: 9 additions & 0 deletions lib/lotus/routing/resources.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,15 @@ class Resources < Resource
# @api private
# @since 0.1.0
self.collection = Resources::CollectionAction

# Return wildcard param between slashs
#
# @api private
# @since x.x.x
def wildcard_param(route_param = nil)
sigularized_param = Lotus::Utils::String.new(route_param).singularize
"#{SLASH}:#{sigularized_param}_id#{SLASH}"
end
end
end
end
20 changes: 20 additions & 0 deletions lib/lotus/routing/resources/action.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,31 @@ class Action < Resource::Action
self.identifier = ':id'.freeze
end

# Pluralize concrete actions
#
# @api private
# @since x.x.x
module PluralizedAction
private
# The name of the RESTful action.
#
# @api private
# @since x.x.x
def as
Lotus::Utils::String.new(super).pluralize
end
end

# Collection action
# It implements #collection within a #resources block.
#
# @api private
# @since 0.1.0
# @see Lotus::Router#resources
class CollectionAction < Resource::CollectionAction
def as(action_name)
Lotus::Utils::String.new(super(action_name)).pluralize
end
end

# Member action
Expand Down Expand Up @@ -66,6 +84,7 @@ def path
# @since 0.1.0
# @see Lotus::Router#resources
class Index < Action
include PluralizedAction
self.verb = :get
end

Expand All @@ -83,6 +102,7 @@ class New < Resource::New
# @since 0.1.0
# @see Lotus::Router#resources
class Create < Resource::Create
include PluralizedAction
end

# Show action
Expand Down
Loading

0 comments on commit e45ced3

Please sign in to comment.