lib/roda/plugins/endpoints.rb in roda-endpoints-0.1.0 vs lib/roda/plugins/endpoints.rb in roda-endpoints-0.2.0
- old
+ new
@@ -9,34 +9,64 @@
# Module containing {Roda} plugins.
module RodaPlugins
# Endpoints plugin for {Roda}
module Endpoints
# @param [Class(Roda)] app
- def self.load_dependencies(app)
+ def self.load_dependencies(app, **_opts)
app.plugin :all_verbs
app.plugin :head
app.plugin :caching
app.plugin :monads
app.plugin :symbol_status
app.plugin :symbol_matchers
app.plugin :slash_path_empty
app.plugin :json_parser
app.plugin :indifferent_params
app.plugin :json, classes: [Array, Hash, ROM::Struct]
- return if app.respond_to?(:[])
- require 'dry-container'
- app.extend Dry::Container::Mixin
app.plugin :flow
end
+ # @param [Class(Roda)] app
+ # @param [Hash] opts
+ def self.configure(app, container: app, **opts)
+ opts = (app.opts[:endpoints] || {}).merge(opts)
+ unless container.respond_to? :resolve
+ require 'dry-container'
+ container.extend Dry::Container::Mixin
+ end
+ app.opts[:endpoints] = opts.merge(container: container)
+ Roda::Endpoints.roda_class ||= app
+ end
+
+ # {ClassMethods#register `Roda.register`} &&
+ # {ClassMethods#merge `Roda.merge`}
+ module ClassMethods
+ # @param [String, Symbol] name
+ # @param [Array] args
+ # @param [Proc] block
+ def register(name, *args, &block)
+ opts[:container].register(name, *args, &block)
+ end
+
+ # @param [String, Symbol] name
+ # @param [Array] args
+ # @param [Proc] block
+ def merge(name, *args, &block)
+ opts[:container].merge(name, *args, &block)
+ end
+ end
+
# `Roda::RodaRequest` instant extensions.
+ # rubocop:disable Metrics/ModuleLength
module RequestMethods
# Implements collection endpoint using given args
#
# @param name [Symbol]
# @param item [{Symbol=>Object}]
# @param kwargs [{Symbol=>Object}]
+ # @param type [Class(Roda::Endpoints::Endpoint::Collection)]
+ # @param on [String, Symbol]
# @param (see Endpoint::Collection#initialize)
# @see Endpoint::Collection.defaults
# @yieldparam endpoint [Collection]
# @yieldreturn [#to_json]
# @return [Endpoint]
@@ -62,35 +92,32 @@
# articles.call(:post, r.params)
# end
#
# r.child :id, only: %i(get delete)
# end
- def collection(name, item: { by: :id }, path: name, **kwargs)
- endpoint = Roda::Endpoints::Endpoint::Collection.new(
- name: name,
- container: roda_class,
- item: item,
- **kwargs
- )
- endpoints.push endpoint
- on path.to_s do
- # @route /:name
+ def collection(name,
+ item: { on: :id },
+ type: Roda::Endpoints::Endpoint::Collection,
+ on: name.to_s,
+ **kwargs)
+ endpoint name: name,
+ item: item,
+ type: type,
+ on: on,
+ **kwargs do |endpoint|
yield endpoint if block_given?
- instance_exec(self, endpoint, &endpoint.route)
end
- endpoints.pop #=> endpoint
end
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
- # @param [Symbol] by
- # @param [Endpoint::Collection] collection
- # @param [Hash] kwargs
+ # @param on [Symbol]
+ # @param kwargs [Hash]
#
# @example
# r.collection :articles do |articles|
- # r.child :id
+ # r.item :id
# end
#
# # is equivalent to
#
# r.collection :articles do |articles|
@@ -103,28 +130,79 @@
# r.get do
# article
# end
# end
# end
- def child(by: :id, collection: endpoint, **kwargs)
+ def item(on: :id,
+ type: Roda::Endpoints::Endpoint::Item,
+ **kwargs)
+ unless current_endpoint.is_a?(Roda::Endpoints::Endpoint::Collection)
+ raise ArgumentError,
+ "#{self.class}#item called not within a collection endpoint"
+ end
# @route /{collection.name}/{id}
- on by do |identifier|
- item = collection.child(id: identifier, identifier: by, **kwargs)
- endpoints.push item
- yield item if block_given?
- instance_exec(self, item, &item.route)
- endpoints.pop
+ endpoint(
+ on: on,
+ name: current_endpoint.item_name,
+ type: type,
+ **kwargs
+ ) do |endpoint|
+ yield endpoint if block_given?
end
end
+ # @overload singleton(name, entity, type:, **kwargs)
+ # @overload singleton(name:, entity:, type:, **kwargs)
+ def singleton(*args,
+ name: args.first,
+ entity: args.last,
+ type: Roda::Endpoints::Endpoint::Singleton,
+ **kwargs)
+ endpoint(
+ name: name,
+ entity: entity,
+ type: type,
+ **kwargs
+ ) do |endpoint|
+ yield endpoint if block_given?
+ end
+ end
+
private
+ # @param [Class(Roda::Endpoints::Endpoint::Singleton)] type
+ # @param [Dry::Container::Mixin, #register, #resolve, #merge] container
+ # @param [Roda::Endpoints::Endpoint] parent
+ # @param [Hash] kwargs
+ # rubocop:disable Metrics/ParameterLists
+ def endpoint(name:,
+ type:,
+ container: roda_class.opts[:endpoints][:container],
+ parent: current_endpoint,
+ on: name,
+ **kwargs)
+ on on do |*captures|
+ with_current_endpoint parent.child(
+ name: name,
+ type: type,
+ container: container,
+ parent: parent,
+ on: on,
+ captures: captures,
+ **kwargs
+ ) do |endpoint|
+ yield endpoint if block_given?
+ instance_exec(self, endpoint, &endpoint.route)
+ end
+ end
+ end
+
# @param [Symbol] verb
def match_transaction(verb)
- resolve endpoint.transactions.key_for(verb) do |transaction|
+ resolve current_endpoint.transactions.key_for(verb) do |transaction|
transaction.call(params) do |m|
- statuses = endpoint.class.statuses[verb]
+ statuses = current_endpoint.class.statuses[verb]
m.success do |result|
response.status = statuses[:success]
result
end
@@ -141,20 +219,29 @@
end
end
end
# @return [Endpoint]
- def endpoint
+ def current_endpoint
endpoints.last
end
# @return [<Endpoint>]
def endpoints
@endpoints ||= [Roda::Endpoints::Endpoint.new(
- name: :root, container: roda_class
+ name: :root,
+ ns: nil,
+ container: roda_class.opts[:endpoints][:container]
)]
end
+
+ def with_current_endpoint(endpoint)
+ endpoints.push endpoint
+ yield endpoint
+ endpoints.pop
+ end
end
+ # rubocop:enable Metrics/ModuleLength
end
register_plugin :endpoints, Endpoints
end
end