cogy 0.0.3 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +20 -0
  3. data/README.md +140 -52
  4. data/Rakefile +4 -14
  5. data/app/controllers/cogy/cogy_controller.rb +26 -5
  6. data/app/views/cogy/error.text.erb +1 -1
  7. data/lib/cogy/command.rb +33 -16
  8. data/lib/cogy/context.rb +52 -0
  9. data/lib/cogy/engine.rb +2 -8
  10. data/lib/cogy/invocation.rb +37 -0
  11. data/lib/cogy/version.rb +1 -1
  12. data/lib/cogy.rb +111 -20
  13. data/lib/generators/cogy/config_generator.rb +15 -0
  14. data/lib/generators/cogy/install_generator.rb +25 -0
  15. data/lib/generators/cogy/templates/cogy_config.rb +8 -0
  16. data/lib/generators/cogy/templates/cogy_folder_readme.md +4 -0
  17. data/lib/generators/cogy/templates/command_file.rb +8 -0
  18. data/test/dummy/cogy/foo.rb +24 -0
  19. data/test/dummy/cogy/fully_fledged.rb +14 -0
  20. data/test/dummy/config/application.rb +3 -4
  21. data/test/dummy/config/environments/development.rb +4 -4
  22. data/test/dummy/config/environments/test.rb +1 -1
  23. data/test/dummy/config/initializers/cogy.rb +10 -0
  24. data/test/dummy/config/routes.rb +2 -1
  25. data/test/dummy/log/development.log +84 -0
  26. data/test/dummy/log/test.log +18184 -0
  27. data/test/integration/command_test.rb +47 -0
  28. data/test/integration/helpers_test.rb +19 -0
  29. data/test/integration/inventory_test.rb +54 -0
  30. data/test/support/helpers.rb +30 -0
  31. data/test/test_helper.rb +4 -10
  32. metadata +71 -13
  33. data/lib/cogy/handler.rb +0 -14
  34. data/test/cogy_test.rb +0 -7
  35. data/test/dummy/app/assets/javascripts/application.js +0 -13
  36. data/test/dummy/app/assets/stylesheets/application.css +0 -15
  37. data/test/integration/navigation_test.rb +0 -8
data/lib/cogy.rb CHANGED
@@ -1,44 +1,104 @@
1
1
  require "cogy/engine"
2
- require "cogy/handler"
3
2
  require "cogy/command"
3
+ require "cogy/context"
4
4
 
5
5
  module Cogy
6
+ # The supported Cog bundle config version.
7
+ #
8
+ # @see http://docs.operable.io/docs/bundle-configs
6
9
  COG_BUNDLE_VERSION = 4
7
10
 
8
- # Holds all the registered Commands. Not to be messed with.
9
- mattr_accessor :commands
11
+ # Holds all the registered {Command} objects. Not to be messed with.
10
12
  @@commands = {}
13
+ mattr_accessor :commands
11
14
 
12
- # Bundle config-related stuff
13
- mattr_accessor :bundle_name
15
+ # The Cog bundle name.
16
+ #
17
+ # Used by {Cogy.bundle_config}.
14
18
  @@bundle_name = "cogy"
19
+ mattr_accessor :bundle_name
15
20
 
16
- mattr_accessor :bundle_description
21
+ # The Cog bundle description.
22
+ #
23
+ # Used by {Cogy.bundle_config}.
17
24
  @@bundle_description = "Cogy-generated commands"
25
+ mattr_accessor :bundle_description
18
26
 
19
- # Can be either a string or an object that responds to `#call` and returns
20
- # a string.
27
+ # The Cog bundle version. Can be either a string or an object that responds
28
+ # to `#call` and returns a string. Used by {Cogy.bundle_config}.
29
+ #
30
+ # Used by {Cogy.bundle_config}.
21
31
  #
22
- # Must be set explicitly
32
+ # @example
33
+ # bundle_version = -> { rand(2).to_s }
34
+ @@bundle_version = "0.0.1"
23
35
  mattr_accessor :bundle_version
24
- @@bundle_version = nil
25
36
 
26
- # The path in the Cog Relay where the command executable is located.
37
+ # The path in the Cog Relay where the cogy executable
38
+ # (ie. https://github.com/skroutz/cogy-bundle/blob/master/commands/cogy) is
39
+ # located.
27
40
  #
28
- # Must be set explicitly.
41
+ # Used by {Cogy.bundle_config}.
42
+ @@executable_path = "/usr/bin/cogy"
29
43
  mattr_accessor :executable_path
30
- @@executable_path = nil
31
44
 
32
- # Paths where the files that define the commands will be searched in
33
- mattr_accessor :command_load_paths
45
+ # Paths where the files that define the commands will be searched in the
46
+ # host application.
34
47
  @@command_load_paths = ["cogy"]
48
+ mattr_accessor :command_load_paths
35
49
 
36
- def self.on(cmd_name, opts = {}, &blk)
37
- cmd = Command.new(cmd_name, opts)
38
- handler = Handler.new(blk)
39
- cmd.register!(handler)
50
+ # Registers a command to Cogy. All the options passed are used solely for
51
+ # generating the bundle config (ie. {Cogy.bundle_config}). The passed block
52
+ # is the code that will get executed when the command is invoked.
53
+ #
54
+ # The last value of the block is what will get printed as the result of the
55
+ # command. It should be a string. If you want to return early in a point
56
+ # inside the block, use `next` instead of `return`.
57
+ #
58
+ # Inside the command block, there are the public attributes of {Context}
59
+ # available.
60
+ #
61
+ # @param cmd_name [String, Symbol] the name of the command. This is how the
62
+ # command will be invoked in the chat.
63
+ # @param [Hash] opts the options to create the command with. All these options
64
+ # are used solely for generating the bundle config for Cog, thus they map
65
+ # directly to Cog's bundle config format.
66
+ # See https://cog-book.operable.io/#_the_config_file for more information.
67
+ # @option opts [Array<Symbol, String>, Symbol, String] :args ([])
68
+ # @option opts [Hash{Symbol=>Hash}] :opts ({})
69
+ # @option opts [String] :desc required
70
+ # @option opts [String] :long_desc (nil)
71
+ # @option opts [String] :examples (nil)
72
+ # @option opts [Array] :rules (["allow"])
73
+ #
74
+ # @example
75
+ # Cogy.on "calc",
76
+ # args: [:a, :b],
77
+ # opts: { op: { description: "The operation to perform", type: "string" } },
78
+ # desc: "Perform an arithmetic operation between two numbers",
79
+ # long_desc: "Operations supported are provided with their respective symbols
80
+ # passed as the --op option.",
81
+ # examples: "Addition: !calc --op + 1 2\n" \
82
+ # "Subtraction: !calc --op - 5 3\n" \
83
+ # "Multiplication: !calc --op * 2 5\n" \
84
+ # "Division: !calc --op / 3 2\",
85
+ # rules: ["allow"] do
86
+ # result = args.map(&:to_i).inject(&opts["op"].to_sym)
87
+ # "Hello #{user}, the answer is: #{result}"
88
+ # end
89
+ #
90
+ # @return [void]
91
+ #
92
+ # @note If you want to return early in a point inside a command block,
93
+ # `next` should be used instead of `return`, due to the way Proc objects
94
+ # work in Ruby.
95
+ def self.on(cmd_name, opts = {}, &handler)
96
+ cmd = Command.new(cmd_name, handler, opts)
97
+ cmd.register!
40
98
  end
41
99
 
100
+ # Generates the bundle config
101
+ #
42
102
  # @return [Hash]
43
103
  def self.bundle_config
44
104
  version = if bundle_version.respond_to?(:call)
@@ -52,9 +112,10 @@ module Cogy
52
112
  "name" => bundle_name,
53
113
  "description" => bundle_description,
54
114
  "version" => version,
55
- "commands" => {}
56
115
  }
57
116
 
117
+ config["commands"] = {} if commands.present?
118
+
58
119
  commands.each do |name, cmd|
59
120
  config["commands"][name] = {
60
121
  "executable" => executable_path,
@@ -82,7 +143,37 @@ module Cogy
82
143
  config
83
144
  end
84
145
 
146
+ # Configures Cogy according to the passed block.
147
+ #
148
+ # @example
149
+ # Cogy.configure do |c|
150
+ # c.bundle_name = "foo"
151
+ # end
152
+ #
153
+ # @yield [self] yields {Cogy}
154
+ # @return [void]
85
155
  def self.configure
86
156
  yield self
87
157
  end
158
+
159
+ # Defines a user helper method that can be used throughout commands.
160
+ #
161
+ # @param [Symbol] name the name of the helper
162
+ # @param [Proc] blk the helper body
163
+ #
164
+ # @return [void]
165
+ #
166
+ # @note User helpers also have access to the default helpers like `user`, `env`
167
+ # etc.
168
+ #
169
+ # @example
170
+ # Cogy.configure do |c|
171
+ # helper(:user) { User.find_by(slack_handle: handle) }
172
+ #
173
+ # # a helper that accepts an argument
174
+ # helper(:format) { |answer| answer.titleize }
175
+ # end
176
+ def self.helper(name, &blk)
177
+ Context.class_eval { define_method(name, blk) }
178
+ end
88
179
  end
@@ -0,0 +1,15 @@
1
+ module Cogy
2
+ module Generators
3
+ class ConfigGenerator < Rails::Generators::Base
4
+ source_root File.expand_path("../templates", __FILE__)
5
+
6
+ desc <<DESC
7
+ Description:
8
+ Copies Cogy configuration file to your application's initializer directory.
9
+ DESC
10
+ def copy_config_file
11
+ template 'cogy_config.rb', 'config/initializers/cogy.rb'
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,25 @@
1
+ module Cogy
2
+ module Generators
3
+ class Install < Rails::Generators::Base
4
+ source_root File.expand_path("../templates", __FILE__)
5
+
6
+ desc <<DESC
7
+ Description:
8
+ Mount the engine, create a sample command and add a configuration file
9
+ DESC
10
+
11
+ def run_config_generator
12
+ generate "cogy:config"
13
+ end
14
+
15
+ def copy_sample_command_and_readme
16
+ template 'command_file.rb', 'cogy/general.rb'
17
+ template 'cogy_folder_readme.md', 'cogy/README.md'
18
+ end
19
+
20
+ def mount_engine
21
+ route 'mount Cogy::Engine, at: "/cogy"'
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,8 @@
1
+ # See https://github.com/skroutz/cogy#configuration
2
+ Cogy.configure do |config|
3
+ #config.bundle_name = "myapp"
4
+ #config.bundle_description = "Cog commands generated from myapp"
5
+ #config.bundle_version = "0.0.1"
6
+ #config.executable_path = "/usr/bin/cogy"
7
+ #config.command_load_paths = ["cogy"]
8
+ end
@@ -0,0 +1,4 @@
1
+ Cogy commands live in this directory. If you want to change it, remember
2
+ to update the `command_load_paths` configuration option accordingly.
3
+
4
+ All Ruby files in here are loaded by Cogy when the application boots.
@@ -0,0 +1,8 @@
1
+ # This is a sample file generated by Cogy. Feel free to remove it or customize
2
+ # it as needed.
3
+ #
4
+ # See https://github.com/skroutz/cogy
5
+
6
+ on "foo", desc: "Echoes a foo" do
7
+ "foo"
8
+ end
@@ -0,0 +1,24 @@
1
+ on "say_foo", desc: "Print a foo" do
2
+ "foo"
3
+ end
4
+
5
+ on "raiser", desc: "Raises an exception" do
6
+ raise "boom"
7
+ end
8
+
9
+ on "print_env", desc: "Test cogy env access" do
10
+ env["cogy_foo"]
11
+ end
12
+
13
+ on "foohelper", desc: "" do
14
+ foo
15
+ end
16
+
17
+ on "rails_url_helpers", desc: "" do
18
+ "#{baz_url(host: "dummy.com")} #{baz_path}"
19
+ end
20
+
21
+ on "titleize", desc: "" do
22
+ bar "this should be titleized"
23
+ end
24
+
@@ -0,0 +1,14 @@
1
+ on "calc",
2
+ args: [:a, :b],
3
+ opts: { op: { description: "The operation to perform", type: "string" } },
4
+ desc: "Perform an arithmetic operation between two numbers",
5
+ long_desc: "Operations supported are provided with their respective symbols
6
+ passed as the --op option.",
7
+ examples: "Addition:\n\n !calc --op + 1 2\n\n" \
8
+ "Subtraction:\n\n !calc --op - 5 3\n\n" \
9
+ "Multiplication:\n\n !calc --op * 2 5\n\n" \
10
+ "Division:\n\n !calc --op / 30 2\n\n",
11
+ rules: ["allow"] do
12
+ result = args.map(&:to_i).inject(&opts["op"].to_sym)
13
+ "Hello #{handle}, the answer is: #{result}"
14
+ end
@@ -1,6 +1,8 @@
1
1
  require File.expand_path('../boot', __FILE__)
2
2
 
3
- require 'rails/all'
3
+ require "action_controller/railtie"
4
+ require "action_view/railtie"
5
+ require "rails/test_unit/railtie"
4
6
 
5
7
  Bundler.require(*Rails.groups)
6
8
  require "cogy"
@@ -18,9 +20,6 @@ module Dummy
18
20
  # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
19
21
  # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
20
22
  # config.i18n.default_locale = :de
21
-
22
- # Do not swallow errors in after_commit/after_rollback callbacks.
23
- config.active_record.raise_in_transactional_callbacks = true
24
23
  end
25
24
  end
26
25
 
@@ -14,22 +14,22 @@ Rails.application.configure do
14
14
  config.action_controller.perform_caching = false
15
15
 
16
16
  # Don't care if the mailer can't send.
17
- config.action_mailer.raise_delivery_errors = false
17
+ # config.action_mailer.raise_delivery_errors = false
18
18
 
19
19
  # Print deprecation notices to the Rails logger.
20
20
  config.active_support.deprecation = :log
21
21
 
22
22
  # Raise an error on page load if there are pending migrations.
23
- config.active_record.migration_error = :page_load
23
+ # config.active_record.migration_error = :page_load
24
24
 
25
25
  # Debug mode disables concatenation and preprocessing of assets.
26
26
  # This option may cause significant delays in view rendering with a large
27
27
  # number of complex assets.
28
- config.assets.debug = true
28
+ # config.assets.debug = true
29
29
 
30
30
  # Asset digests allow you to set far-future HTTP expiration dates on all assets,
31
31
  # yet still be able to expire them through the digest params.
32
- config.assets.digest = true
32
+ # config.assets.digest = true
33
33
 
34
34
  # Adds additional error checking when serving assets at runtime.
35
35
  # Checks for improperly declared sprockets dependencies.
@@ -29,7 +29,7 @@ Rails.application.configure do
29
29
  # Tell Action Mailer not to deliver emails to the real world.
30
30
  # The :test delivery method accumulates sent emails in the
31
31
  # ActionMailer::Base.deliveries array.
32
- config.action_mailer.delivery_method = :test
32
+ # config.action_mailer.delivery_method = :test
33
33
 
34
34
  # Randomize the order test cases are executed.
35
35
  config.active_support.test_order = :random
@@ -0,0 +1,10 @@
1
+ Cogy.configure do |c|
2
+ c.bundle_name = "foo"
3
+ c.bundle_description = "The bundle you really need"
4
+ c.bundle_version = "0.0.1"
5
+ c.executable_path = "/usr/bin/foo"
6
+ c.command_load_paths = ["cogy"]
7
+
8
+ c.helper(:foo) { env["cogy_foo"] }
9
+ c.helper(:bar) { |text| text.titleize }
10
+ end
@@ -1,4 +1,5 @@
1
1
  Rails.application.routes.draw do
2
-
3
2
  mount Cogy::Engine => "/cogy"
3
+
4
+ get "baz" => "cogy#cmd"
4
5
  end
@@ -0,0 +1,84 @@
1
+
2
+
3
+ Started GET "/cogy/inventory" for 127.0.0.1 at 2016-11-10 10:43:03 +0200
4
+ Processing by Cogy::CogyController#inventory as */*
5
+ Rendered text template (0.0ms)
6
+ Completed 200 OK in 8ms (Views: 6.8ms)
7
+
8
+
9
+ Started GET "/cogy/cmd/say_foo" for 127.0.0.1 at 2016-11-10 10:43:08 +0200
10
+
11
+ ActionController::RoutingError (No route matches [GET] "/cogy/cmd/say_foo"):
12
+ actionpack (4.2.7.1) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call'
13
+ actionpack (4.2.7.1) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
14
+ railties (4.2.7.1) lib/rails/rack/logger.rb:38:in `call_app'
15
+ railties (4.2.7.1) lib/rails/rack/logger.rb:20:in `block in call'
16
+ activesupport (4.2.7.1) lib/active_support/tagged_logging.rb:68:in `block in tagged'
17
+ activesupport (4.2.7.1) lib/active_support/tagged_logging.rb:26:in `tagged'
18
+ activesupport (4.2.7.1) lib/active_support/tagged_logging.rb:68:in `tagged'
19
+ railties (4.2.7.1) lib/rails/rack/logger.rb:20:in `call'
20
+ actionpack (4.2.7.1) lib/action_dispatch/middleware/request_id.rb:21:in `call'
21
+ rack (1.6.4) lib/rack/methodoverride.rb:22:in `call'
22
+ rack (1.6.4) lib/rack/runtime.rb:18:in `call'
23
+ activesupport (4.2.7.1) lib/active_support/cache/strategy/local_cache_middleware.rb:28:in `call'
24
+ rack (1.6.4) lib/rack/lock.rb:17:in `call'
25
+ actionpack (4.2.7.1) lib/action_dispatch/middleware/static.rb:120:in `call'
26
+ rack (1.6.4) lib/rack/sendfile.rb:113:in `call'
27
+ railties (4.2.7.1) lib/rails/engine.rb:518:in `call'
28
+ railties (4.2.7.1) lib/rails/application.rb:165:in `call'
29
+ rack (1.6.4) lib/rack/lock.rb:17:in `call'
30
+ rack (1.6.4) lib/rack/content_length.rb:15:in `call'
31
+ rack (1.6.4) lib/rack/handler/webrick.rb:88:in `service'
32
+ /Users/agis/.rubies/ruby-2.1.9/lib/ruby/2.1.0/webrick/httpserver.rb:138:in `service'
33
+ /Users/agis/.rubies/ruby-2.1.9/lib/ruby/2.1.0/webrick/httpserver.rb:94:in `run'
34
+ /Users/agis/.rubies/ruby-2.1.9/lib/ruby/2.1.0/webrick/server.rb:295:in `block in start_thread'
35
+
36
+
37
+ Rendered /Users/agis/.gem/ruby/2.1.9/gems/actionpack-4.2.7.1/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (1.1ms)
38
+ Rendered /Users/agis/.gem/ruby/2.1.9/gems/actionpack-4.2.7.1/lib/action_dispatch/middleware/templates/routes/_route.html.erb (0.5ms)
39
+ Rendered /Users/agis/.gem/ruby/2.1.9/gems/actionpack-4.2.7.1/lib/action_dispatch/middleware/templates/routes/_route.html.erb (0.1ms)
40
+ Rendered /Users/agis/.gem/ruby/2.1.9/gems/actionpack-4.2.7.1/lib/action_dispatch/middleware/templates/routes/_table.html.erb (9.7ms)
41
+ Rendered /Users/agis/.gem/ruby/2.1.9/gems/actionpack-4.2.7.1/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (8.3ms)
42
+ Rendered /Users/agis/.gem/ruby/2.1.9/gems/actionpack-4.2.7.1/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb within rescues/layout (40.3ms)
43
+
44
+
45
+ Started GET "/cogy/cmd/agis/say_foo" for 127.0.0.1 at 2016-11-10 10:43:25 +0200
46
+ Processing by Cogy::CogyController#command as */*
47
+ Parameters: {"cmd"=>"agis", "user"=>"say_foo"}
48
+ Rendered /Users/agis/dev/cogy/app/views/cogy/error.text.erb (0.4ms)
49
+ Completed 200 OK in 4ms (Views: 3.5ms)
50
+
51
+
52
+ Started GET "/cogy/cmd/agifdsas/say_foo" for 127.0.0.1 at 2016-11-10 10:44:46 +0200
53
+ Processing by Cogy::CogyController#command as */*
54
+ Parameters: {"cmd"=>"agifdsas", "user"=>"say_foo"}
55
+ Rendered /Users/agis/dev/cogy/app/views/cogy/error.text.erb (0.0ms)
56
+ Completed 200 OK in 2ms (Views: 1.7ms)
57
+
58
+
59
+ Started GET "/cogy/cmd/calc/agis?cog_opt_op=%2B" for 127.0.0.1 at 2016-11-10 13:14:05 +0200
60
+ Processing by Cogy::CogyController#command as */*
61
+ Parameters: {"cog_opt_op"=>"+", "cmd"=>"calc", "user"=>"agis"}
62
+ Rendered text template (0.0ms)
63
+ Completed 200 OK in 38528ms (Views: 11.3ms)
64
+
65
+
66
+ Started GET "/cogy/cmd/calc/agis?cog_opt_op=%2B&cog_argv_0=1&cog_argv_1=2" for 127.0.0.1 at 2016-11-10 13:14:50 +0200
67
+ Processing by Cogy::CogyController#command as */*
68
+ Parameters: {"cog_opt_op"=>"+", "cog_argv_0"=>"1", "cog_argv_1"=>"2", "cmd"=>"calc", "user"=>"agis"}
69
+ Rendered text template (0.0ms)
70
+ Completed 200 OK in 12746ms (Views: 0.4ms)
71
+
72
+
73
+ Started GET "/cogy/cmd/raiser/foo" for ::1 at 2016-11-10 15:26:14 +0200
74
+ Processing by Cogy::CogyController#command as HTML
75
+ Parameters: {"cmd"=>"raiser", "user"=>"foo"}
76
+ Rendered /Users/agis/dev/cogy/app/views/cogy/error.text.erb (1.0ms)
77
+ Completed 500 Internal Server Error in 8ms (Views: 7.5ms)
78
+
79
+
80
+ Started GET "/cogy/cmd/raiser/foo" for ::1 at 2016-11-10 15:26:20 +0200
81
+ Processing by Cogy::CogyController#command as HTML
82
+ Parameters: {"cmd"=>"raiser", "user"=>"foo"}
83
+ Rendered /Users/agis/dev/cogy/app/views/cogy/error.text.erb (0.1ms)
84
+ Completed 500 Internal Server Error in 3ms (Views: 2.1ms)