lib/cogy.rb in cogy-0.0.3 vs lib/cogy.rb in cogy-0.1.0
- old
+ new
@@ -1,46 +1,106 @@
require "cogy/engine"
-require "cogy/handler"
require "cogy/command"
+require "cogy/context"
module Cogy
+ # The supported Cog bundle config version.
+ #
+ # @see http://docs.operable.io/docs/bundle-configs
COG_BUNDLE_VERSION = 4
- # Holds all the registered Commands. Not to be messed with.
- mattr_accessor :commands
+ # Holds all the registered {Command} objects. Not to be messed with.
@@commands = {}
+ mattr_accessor :commands
- # Bundle config-related stuff
- mattr_accessor :bundle_name
+ # The Cog bundle name.
+ #
+ # Used by {Cogy.bundle_config}.
@@bundle_name = "cogy"
+ mattr_accessor :bundle_name
- mattr_accessor :bundle_description
+ # The Cog bundle description.
+ #
+ # Used by {Cogy.bundle_config}.
@@bundle_description = "Cogy-generated commands"
+ mattr_accessor :bundle_description
- # Can be either a string or an object that responds to `#call` and returns
- # a string.
+ # The Cog bundle version. Can be either a string or an object that responds
+ # to `#call` and returns a string. Used by {Cogy.bundle_config}.
#
- # Must be set explicitly
+ # Used by {Cogy.bundle_config}.
+ #
+ # @example
+ # bundle_version = -> { rand(2).to_s }
+ @@bundle_version = "0.0.1"
mattr_accessor :bundle_version
- @@bundle_version = nil
- # The path in the Cog Relay where the command executable is located.
+ # The path in the Cog Relay where the cogy executable
+ # (ie. https://github.com/skroutz/cogy-bundle/blob/master/commands/cogy) is
+ # located.
#
- # Must be set explicitly.
+ # Used by {Cogy.bundle_config}.
+ @@executable_path = "/usr/bin/cogy"
mattr_accessor :executable_path
- @@executable_path = nil
- # Paths where the files that define the commands will be searched in
- mattr_accessor :command_load_paths
+ # Paths where the files that define the commands will be searched in the
+ # host application.
@@command_load_paths = ["cogy"]
+ mattr_accessor :command_load_paths
- def self.on(cmd_name, opts = {}, &blk)
- cmd = Command.new(cmd_name, opts)
- handler = Handler.new(blk)
- cmd.register!(handler)
+ # Registers a command to Cogy. All the options passed are used solely for
+ # generating the bundle config (ie. {Cogy.bundle_config}). The passed block
+ # is the code that will get executed when the command is invoked.
+ #
+ # The last value of the block is what will get printed as the result of the
+ # command. It should be a string. If you want to return early in a point
+ # inside the block, use `next` instead of `return`.
+ #
+ # Inside the command block, there are the public attributes of {Context}
+ # available.
+ #
+ # @param cmd_name [String, Symbol] the name of the command. This is how the
+ # command will be invoked in the chat.
+ # @param [Hash] opts the options to create the command with. All these options
+ # are used solely for generating the bundle config for Cog, thus they map
+ # directly to Cog's bundle config format.
+ # See https://cog-book.operable.io/#_the_config_file for more information.
+ # @option opts [Array<Symbol, String>, Symbol, String] :args ([])
+ # @option opts [Hash{Symbol=>Hash}] :opts ({})
+ # @option opts [String] :desc required
+ # @option opts [String] :long_desc (nil)
+ # @option opts [String] :examples (nil)
+ # @option opts [Array] :rules (["allow"])
+ #
+ # @example
+ # Cogy.on "calc",
+ # args: [:a, :b],
+ # opts: { op: { description: "The operation to perform", type: "string" } },
+ # desc: "Perform an arithmetic operation between two numbers",
+ # long_desc: "Operations supported are provided with their respective symbols
+ # passed as the --op option.",
+ # examples: "Addition: !calc --op + 1 2\n" \
+ # "Subtraction: !calc --op - 5 3\n" \
+ # "Multiplication: !calc --op * 2 5\n" \
+ # "Division: !calc --op / 3 2\",
+ # rules: ["allow"] do
+ # result = args.map(&:to_i).inject(&opts["op"].to_sym)
+ # "Hello #{user}, the answer is: #{result}"
+ # end
+ #
+ # @return [void]
+ #
+ # @note If you want to return early in a point inside a command block,
+ # `next` should be used instead of `return`, due to the way Proc objects
+ # work in Ruby.
+ def self.on(cmd_name, opts = {}, &handler)
+ cmd = Command.new(cmd_name, handler, opts)
+ cmd.register!
end
+ # Generates the bundle config
+ #
# @return [Hash]
def self.bundle_config
version = if bundle_version.respond_to?(:call)
bundle_version.call
else
@@ -50,13 +110,14 @@
config = {
"cog_bundle_version" => COG_BUNDLE_VERSION,
"name" => bundle_name,
"description" => bundle_description,
"version" => version,
- "commands" => {}
}
+ config["commands"] = {} if commands.present?
+
commands.each do |name, cmd|
config["commands"][name] = {
"executable" => executable_path,
"description" => cmd.desc,
"rules" => cmd.rules
@@ -80,9 +141,39 @@
end
config
end
+ # Configures Cogy according to the passed block.
+ #
+ # @example
+ # Cogy.configure do |c|
+ # c.bundle_name = "foo"
+ # end
+ #
+ # @yield [self] yields {Cogy}
+ # @return [void]
def self.configure
yield self
+ end
+
+ # Defines a user helper method that can be used throughout commands.
+ #
+ # @param [Symbol] name the name of the helper
+ # @param [Proc] blk the helper body
+ #
+ # @return [void]
+ #
+ # @note User helpers also have access to the default helpers like `user`, `env`
+ # etc.
+ #
+ # @example
+ # Cogy.configure do |c|
+ # helper(:user) { User.find_by(slack_handle: handle) }
+ #
+ # # a helper that accepts an argument
+ # helper(:format) { |answer| answer.titleize }
+ # end
+ def self.helper(name, &blk)
+ Context.class_eval { define_method(name, blk) }
end
end