cogy 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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)