speedflow 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5dbf2b0268766ac602d031b032f4a050893a0c70
4
+ data.tar.gz: b80f540563d169c40148ec7ec5345566e8c230fc
5
+ SHA512:
6
+ metadata.gz: de2a65663c9b74ed32dd28e5f5273aa472fd3137fbb25a799cb8ebd97525b99c17e72b0db16669a73d774bdfa93c84857bd63233fc54d16ae0b6e816c14615fa
7
+ data.tar.gz: 221cd775cb9bbfc581a39a0b6a0b3717f12c8cd769c8698fa103b91080fdf5e5e4db4007fbe869cbd196d705fab3de7ba21ea2891d82567ed573448295f753af
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Speedflow
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,34 @@
1
+ # <img src="https://raw.githubusercontent.com/speedflow/speedflow/master/resources/logo.png" alt="Speedflow" height="40" />
2
+
3
+ [![Build Status](https://travis-ci.org/speedflow/speedflow.svg?branch=master)](https://travis-ci.org/speedflow/speedflow)
4
+ [![Gem Version](https://badge.fury.io/rb/speedflow.svg)](https://badge.fury.io/rb/speedflow)
5
+ [![Code Climate](https://codeclimate.com/github/speedflow/speedflow/badges/gpa.svg)](https://codeclimate.com/github/speedflow/speedflow)
6
+ [![Test Coverage](https://codeclimate.com/github/speedflow/speedflow/badges/coverage.svg)](https://codeclimate.com/github/speedflow/speedflow/coverage)
7
+ [![Inline docs](http://inch-ci.org/github/speedflow/speedflow.svg?branch=master)](http://inch-ci.org/github/speedflow/speedflow)
8
+
9
+
10
+ Speedflow provides a robust system to transform your painful workflow :rage: in a sweet workflow :relaxed:.
11
+ Several [plugins](https://github.com/speedflow?utf8=%E2%9C%93&query=speedflow-) :package: are availables to help you to keep your time :clock1:.
12
+
13
+ ## Philosophy
14
+
15
+ When you work with some different tools, the workflow can be transform to a Rube Goldberg machine... and can be very painful.
16
+ The idea of Speedflow™ is very simple, he offer a glue between different tools like Jira, Trello, Git and others...
17
+
18
+ ## Getting Started
19
+
20
+ * [Install](https://github.com/speedflow/speedflow/wiki/Installation) the gem
21
+ * [Install](https://github.com/speedflow/speedflow/wiki/Plugins) the plugins
22
+
23
+ ## The Core Speedflow Team
24
+
25
+ * [Julien Breux](https://github.com/JulienBreux) - Author
26
+ * [Emmanuel Julliot](https://github.com/emmanueljulliot) - Logo Designer
27
+
28
+ ## Donate
29
+
30
+ I maintain this project in my free time, if it helped you please support my work [via paypal](https://paypal.me/JulienBreux), thanks a lot!
31
+
32
+ ## License
33
+
34
+ See [LICENSE](https://github.com/speedflow/speedflow/blob/master/LICENSE).
data/bin/console ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'speedflow'
5
+ require 'pry'
6
+
7
+ Pry.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/bin/speedflow ADDED
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ruby
2
+ STDOUT.sync = true
3
+
4
+ require 'mercenary'
5
+ require 'speedflow'
6
+
7
+ # Speedflow program
8
+ Mercenary.program(:speedflow) do |program|
9
+ program.version Speedflow::VERSION
10
+ program.description 'Speedflow is a CLI tool to help you to keep your time.'
11
+ program.syntax "speedflow [OPTIONS] COMMAND [arg...]\n" \
12
+ ' speedflow [ --help | -v | --version | --trace ]'
13
+ program.option(
14
+ 'config',
15
+ '-c FILE1[,FILE2[,FILE3...]]',
16
+ '--config FILE1[,FILE2[,FILE3...]]',
17
+ Array,
18
+ 'Custom configuration file')
19
+
20
+ # program.logger(Logger::DEBUG)
21
+
22
+ Speedflow::Command.subclasses.each { |c| c.init_with_program(program) }
23
+
24
+ program.default_command(:help)
25
+ end
@@ -0,0 +1,100 @@
1
+ module Speedflow
2
+ # Used to manage the commands
3
+ class Command
4
+ class << self
5
+ include Message
6
+
7
+ # @return [Hash] List of arguments
8
+ attr_writer :argv
9
+
10
+ # A list of subclasses of Speedflow::Command
11
+ #
12
+ # Returns Array of commands.
13
+ def subclasses
14
+ @subclasses ||= []
15
+ end
16
+
17
+ # Keep a list of subclasses of Speedflow::Command every time it's
18
+ # inherited. Called automatically.
19
+ #
20
+ # base - the subclass
21
+ #
22
+ # Returns nothing.
23
+ def inherited(base)
24
+ subclasses << base
25
+ super(base)
26
+ end
27
+
28
+ # Speedflow configuration with the options passed in as overrides
29
+ #
30
+ # options - the configuration overrides
31
+ #
32
+ # Returns a full Speedflow configuration.
33
+ def config_from_options(options)
34
+ Speedflow::Configuration.get(options)
35
+ rescue ConfigurationFileNotFound => exception
36
+ error exception.message
37
+ abort
38
+ rescue ConfigurationFileFormat => exception
39
+ error exception.message
40
+ abort
41
+ end
42
+
43
+ # Public: Get config from fresh options
44
+ #
45
+ # program - Program.
46
+ # command - Commad.
47
+ # options - Options.
48
+ #
49
+ # Returns configuration Hash.
50
+ def config_from_fresh_options(program, command, options = {})
51
+ execute_from_option(program, command, 'config') do |value|
52
+ options = { config: value }
53
+ end
54
+
55
+ config_from_options(options)
56
+ end
57
+
58
+ # Public: Exectute option from key
59
+ #
60
+ # prog - Program.
61
+ # command - Commad.
62
+ # opt_key - Option key.
63
+ #
64
+ # Returns nothing.
65
+ def execute_from_option(prog, command, opt_key)
66
+ opt_index = prog.options.find_index { |o| o.config_key == opt_key }
67
+ opt = prog.options[opt_index]
68
+ opt_parser = OptionParser.new do |opts|
69
+ command.add_default_options(opts)
70
+ opts.on(*opt.for_option_parser) { |value| yield(value) }
71
+ end
72
+
73
+ # rubocop:disable HandleExceptions
74
+ begin
75
+ opt_parser.parse(argv)
76
+ rescue OptionParser::InvalidOption
77
+ # Nothing.
78
+ end
79
+ # rubocop:enable HandleExceptions
80
+ end
81
+
82
+ # Display invalid command.
83
+ #
84
+ # cmd - the command
85
+ #
86
+ # Returns nothing
87
+ def invalid_command(cmd)
88
+ error "Command not found '#{cmd}'."
89
+ notice 'Please, use --help to display valid commands.'
90
+ end
91
+
92
+ # Public: Define argv (used to test)
93
+ #
94
+ # Returns Array of argv.
95
+ def argv
96
+ @argv ||= ARGV
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,106 @@
1
+ module Speedflow
2
+ module Commands
3
+ # Flow command
4
+ class Flow < Command
5
+ class << self
6
+ include Message
7
+
8
+ # Init command with program.
9
+ #
10
+ # prog - the program.
11
+ #
12
+ # Returns nothing.
13
+ def init_with_program(program)
14
+ program.command(:flow) do |command|
15
+ command.syntax 'flow [trigger]'
16
+ command.description 'Play with the flow, trigger some actions.'
17
+
18
+ add_options_from_flow(program, command)
19
+
20
+ command.action do |args, options|
21
+ config = config_from_options(options)
22
+ trigger = (args.first || '').to_sym
23
+ process(trigger, config, args, options)
24
+ end
25
+ end
26
+ end
27
+
28
+ # Process command.
29
+ #
30
+ # trigger - Trigger name.
31
+ # config - Configuration.
32
+ # args - Arguments.
33
+ # options - Options.
34
+ #
35
+ # Returns nothing.
36
+ def process(trigger, config, args, options)
37
+ if args.empty? || !config.flow_triggers?
38
+ valid_triggers(config['flow'].keys)
39
+ elsif !config.flow_trigger?(trigger)
40
+ invalid_trigger(trigger)
41
+ valid_triggers(config['flow'].keys)
42
+ else
43
+ process_trigger(trigger, config, options)
44
+ end
45
+ end
46
+
47
+ # Process trigger.
48
+ #
49
+ # trigger - Trigger name.
50
+ # config - Configuration.
51
+ # options - Options.
52
+ #
53
+ # Returns nothing.
54
+ def process_trigger(trigger, config, options)
55
+ flow = Speedflow::Flow.new(config)
56
+ begin
57
+ flow.trigger(trigger, options)
58
+ success "Trigger '#{trigger}' successful"
59
+ rescue FlowTriggerNotFound => exception
60
+ error "Trigger '#{trigger}' error: #{exception.message}"
61
+ rescue PluginNotFound => exception
62
+ error "Plugin error: #{exception.message}"
63
+ end
64
+ end
65
+
66
+ # Add options from flow arguents.
67
+ #
68
+ # program - the program.
69
+ # command - the command.
70
+ #
71
+ # Returns nothing.
72
+ def add_options_from_flow(program, command)
73
+ config = config_from_fresh_options(program, command)
74
+ flow = Speedflow::Flow.new(config)
75
+ flow.flat_arguments.each do |argument|
76
+ program.option(
77
+ argument,
78
+ '',
79
+ "--#{argument} #{argument.capitalize}",
80
+ String,
81
+ 'Option form flow.')
82
+ end
83
+ end
84
+
85
+ # Display invalid trigger message.
86
+ #
87
+ # trigger - the trigger name.
88
+ #
89
+ # Returns nothing.
90
+ def invalid_trigger(trigger)
91
+ error "Trigger not found '#{trigger}'."
92
+ end
93
+
94
+ # Display valid trigger message.
95
+ #
96
+ # triggers - Array of triggers.
97
+ #
98
+ # Returns nothing.
99
+ def valid_triggers(triggers)
100
+ info 'List of available triggers:'
101
+ message triggers.join(', ')
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,45 @@
1
+ module Speedflow
2
+ module Commands
3
+ # Help command
4
+ class Help < Command
5
+ class << self
6
+ include Message
7
+
8
+ # Init command with program.
9
+ #
10
+ # prog - the programm
11
+ #
12
+ # Returns nothing.
13
+ def init_with_program(prog)
14
+ prog.command(:help) do |c|
15
+ c.syntax 'help [subcommand]'
16
+ c.description 'Show the help message, optionally for a given ' \
17
+ 'subcommand.'
18
+ c.action do |args, _|
19
+ cmd = (args.first || '').to_sym
20
+ process(cmd, prog, args)
21
+ end
22
+ end
23
+ end
24
+
25
+ # Process command.
26
+ #
27
+ # cmd - Command.
28
+ # prog - Program.
29
+ # args - Arguments.
30
+ #
31
+ # Returns nothing.
32
+ def process(cmd, prog, args)
33
+ if args.empty?
34
+ puts prog
35
+ elsif prog.has_command? cmd
36
+ puts prog.commands[cmd]
37
+ else
38
+ invalid_command(cmd)
39
+ abort
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,118 @@
1
+ module Speedflow
2
+ # Used to manage configuration in Speedflow core
3
+ class Configuration < Hash
4
+ # Default configuration filename
5
+ DEFAULT_FILENAME = '.speedflow.yml'.freeze
6
+
7
+ # Default options. Overridden by values in .speedflow.yml.
8
+ DEFAULTS = Configuration[{
9
+ version: 1,
10
+ source: Dir.pwd,
11
+ plugins: [],
12
+ flow: {}
13
+ }]
14
+
15
+ # Public: Check triggers in flow
16
+ #
17
+ # Returns if flow has triggers.
18
+ def flow_triggers?
19
+ key?('flow') && !self['flow'].keys.empty?
20
+ end
21
+
22
+ # Public: Check trigger in flow
23
+ #
24
+ # trigger - Trigger name.
25
+ #
26
+ # Returns if trigger exists in flow.
27
+ def flow_trigger?(trigger)
28
+ key?('flow') && self['flow'].key?(trigger.to_s)
29
+ end
30
+
31
+ # Public: Directory of the Speedflow source folder
32
+ #
33
+ # override - the command-line options hash
34
+ #
35
+ # Returns the path to the Speedflow source directory.
36
+ def source(override)
37
+ get_config_value_with_override(:source, override)
38
+ end
39
+
40
+ # Public: Get config value with override
41
+ #
42
+ # config_key - Configuration key.
43
+ # override - An Hash of override values.
44
+ #
45
+ # Returns the value of config key or override.
46
+ def get_config_value_with_override(config_key, override)
47
+ override[config_key] || self[config_key] || DEFAULTS[config_key]
48
+ end
49
+
50
+ # Public: Generate list of configuration files from the override
51
+ #
52
+ # override - the command-line options hash
53
+ #
54
+ # Returns an Array of config files
55
+ def config_files(override)
56
+ files = []
57
+ if override.stringify_keys.key?('config')
58
+ files = override.stringify_keys.delete('config')
59
+ override.delete('config')
60
+ else
61
+ files << source(override) + File::SEPARATOR + DEFAULT_FILENAME
62
+ end
63
+ files = [files] unless files.is_a? Array
64
+ files
65
+ end
66
+
67
+ # Public: Read all files content
68
+ #
69
+ # files - the list of configuration file
70
+ #
71
+ # Returns the full configuration.
72
+ def read_config_files(files)
73
+ config = clone
74
+
75
+ files.each do |file|
76
+ unless File.exist?(file)
77
+ raise ConfigurationFileNotFound, "Unable to load config file: #{file}"
78
+ end
79
+
80
+ config = config.deep_merge(read_config_file(file))
81
+ end
82
+
83
+ config.replace_values_from_env
84
+ end
85
+
86
+ # Public: Read config file
87
+ #
88
+ # file - File to read.
89
+ #
90
+ # Returns a Hash.
91
+ def read_config_file(file)
92
+ SafeYAML.load_file(file) || {}
93
+ rescue
94
+ raise ConfigurationFileFormat, "This file is not a valid YAML: #{file}"
95
+ end
96
+
97
+ # Get all configuration.
98
+ #
99
+ # override - Hash of configuration.
100
+ #
101
+ # Returns the full configuration.
102
+ def self.get(override = {})
103
+ config = self[self::DEFAULTS]
104
+ override = self[override].stringify_keys
105
+
106
+ config = config.read_config_files(config.config_files(override))
107
+ config.deep_merge(override).stringify_keys
108
+ end
109
+ end
110
+
111
+ # File not found exception
112
+ class ConfigurationFileNotFound < Exception
113
+ end
114
+
115
+ # File format exception
116
+ class ConfigurationFileFormat < Exception
117
+ end
118
+ end
@@ -0,0 +1,79 @@
1
+ # Hash core extension
2
+ class Hash
3
+ # Public: Replace values from pattern.
4
+ #
5
+ # pattern - Used to define the pattern to match.
6
+ # hash - Default hash.
7
+ # block - Used to work outside
8
+ #
9
+ # TODO Re-enable Rubocop [...]
10
+ # rubocop:disable MethodLength, PerceivedComplexity, CyclomaticComplexity
11
+ #
12
+ # Returns Hash.
13
+ def replace_values(pattern, hash = nil, &block)
14
+ hash = self if hash.nil?
15
+ hash.each do |hash_key, hash_value|
16
+ if hash_value.is_a?(String) && hash_value =~ pattern
17
+ hash[hash_key] = yield(hash_value)
18
+ elsif hash_value.is_a?(Hash)
19
+ replace_values(pattern, hash_value, &block)
20
+ elsif hash_value.is_a?(Array)
21
+ hash_value.flatten.each_with_index do |array_v, array_i|
22
+ replace_values(pattern, array_v, &block) if array_v.is_a?(Hash)
23
+ hash_value[array_i] = yield(array_v) if array_v.is_a?(String)
24
+ end
25
+ end
26
+ end
27
+ hash
28
+ end
29
+ # rubocop:enable MethodLength, PerceivedComplexity, CyclomaticComplexity
30
+
31
+ # Public: Change Hash values with environment values.
32
+ #
33
+ # Replace {ENV_VAR} by ENV['ENV_VAR'].
34
+ #
35
+ # hash - Hash to change (default is current Hash).
36
+ #
37
+ # Returns Hash.
38
+ def replace_values_from_env(hash = nil)
39
+ pattern = /\{([A-Z0-9_]+)\}/
40
+ replace_values(pattern, hash) do |value|
41
+ value.gsub(pattern) { |m| ENV[m.gsub(pattern, '\1')] }
42
+ end
43
+ end
44
+
45
+ # Public: Replace values from previous values.
46
+ #
47
+ # prev_values - Hash of values.
48
+ # hash - Default hash.
49
+ #
50
+ # Returns Hash.
51
+ def replace_values_from_previous(prev_values, hash = nil)
52
+ pattern = /\{previous\.((?!\.)(?!.*\.\.)[A-Za-z0-9_\.]+(?<!\.))\}/
53
+ replace_values(pattern, hash) do |value|
54
+ value.gsub(pattern) do |m|
55
+ hash_values_from_keys_schema(m.gsub(pattern, '\1'), prev_values)
56
+ end
57
+ end
58
+ end
59
+
60
+ # Public: Get hash value from keys schema
61
+ #
62
+ # keys - String of keys.
63
+ # hash - Hash to parse.
64
+ #
65
+ # Examples
66
+ #
67
+ # hash_values_from_keys_schema('foo.bar', {foo: {bar: 'qux'}})
68
+ # # => 'qux'
69
+ #
70
+ # Returns String value.
71
+ def hash_values_from_keys_schema(keys, hash)
72
+ value = {}
73
+ keys.split('.').each do |key, _|
74
+ value = value.stringify_keys[key] unless value.nil?
75
+ value = hash.stringify_keys[key] if value.nil?
76
+ end
77
+ value
78
+ end
79
+ end
@@ -0,0 +1,82 @@
1
+ module Speedflow
2
+ # Used to manage the flow of Speedflow
3
+ class Flow
4
+ # Public: Constructor.
5
+ #
6
+ # config - Default Hahs of config.
7
+ #
8
+ # Examples
9
+ #
10
+ # Flow.new({})
11
+ # # => <Speedflow::Flow>
12
+ #
13
+ # Returns a Hash of config.
14
+ def initialize(config)
15
+ @config = config
16
+ end
17
+
18
+ # Public: Trigger.
19
+ #
20
+ # trigger - Trigger name.
21
+ # inputs - Inputs.
22
+ #
23
+ # Returns nothing.
24
+ def trigger(trigger, inputs)
25
+ unless @config.flow_trigger?(trigger)
26
+ raise FlowTriggerNotFound, "Unable to trigger: #{trigger}"
27
+ end
28
+
29
+ output = {}
30
+ @config['flow'][trigger.to_s].each do |step|
31
+ arguments = step['arguments'] || {}
32
+ step['arguments'] = transform_arguments(arguments, output, inputs)
33
+ step['arguments']['_config'] = @config
34
+ output = plugin_manager.call_action_from_step(step)
35
+ end
36
+ end
37
+
38
+ # Public: Transform arguments (to add value)
39
+ #
40
+ # arguments - Hash of arguments.
41
+ # prev_values - Hash of previous values.
42
+ # inputs - Hash of inputs.
43
+ #
44
+ # Returns Hash of arguments.
45
+ def transform_arguments(arguments, prev_values, inputs)
46
+ arguments = arguments.replace_values_from_previous(prev_values)
47
+ arguments.each do |arg_name, arg_values|
48
+ arguments[arg_name][:value] = ''
49
+ if inputs.key?(arg_name)
50
+ arguments[arg_name][:value] = inputs[arg_name]
51
+ elsif arg_values.key?('default')
52
+ arguments[arg_name][:value] = arg_values[:default]
53
+ end
54
+ end
55
+ arguments
56
+ end
57
+
58
+ # Public: Get flat arguments from flow.
59
+ #
60
+ # Returns flat Array of arguments.
61
+ def flat_arguments
62
+ args = []
63
+ @config['flow'].each do |_, steps|
64
+ steps.each do |s|
65
+ (args << s['arguments'].keys).flatten! unless s['arguments'].nil?
66
+ end
67
+ end
68
+ args.uniq
69
+ end
70
+
71
+ # Plugin manager.
72
+ #
73
+ # Returns an instance of plugin manager.
74
+ def plugin_manager
75
+ @plugin_manager ||= PluginManager.new(@config['plugins'])
76
+ end
77
+ end
78
+
79
+ # Trigger exception.
80
+ class FlowTriggerNotFound < Exception
81
+ end
82
+ end
@@ -0,0 +1,76 @@
1
+ # Speedflow core
2
+ module Speedflow
3
+ require 'colorize'
4
+ # Used to manage the output message
5
+ module Message
6
+ # Public: Message
7
+ #
8
+ # message - Message.
9
+ #
10
+ # Examples
11
+ #
12
+ # message 'Hello'
13
+ # # => nil
14
+ #
15
+ # Returns nothing.
16
+ def message(message)
17
+ puts message.colorize(:white)
18
+ end
19
+
20
+ # Public: Notice
21
+ #
22
+ # message - Message.
23
+ #
24
+ # Examples
25
+ #
26
+ # notice 'Hello'
27
+ # # => nil
28
+ #
29
+ # Returns nothing.
30
+ def notice(message)
31
+ puts message.colorize(:grey)
32
+ end
33
+
34
+ # Public: Info
35
+ #
36
+ # message - Message.
37
+ #
38
+ # Examples
39
+ #
40
+ # info 'Hello'
41
+ # # => nil
42
+ #
43
+ # Returns nothing.
44
+ def info(message)
45
+ puts message.colorize(:light_blue)
46
+ end
47
+
48
+ # Public: Success
49
+ #
50
+ # message - Message.
51
+ #
52
+ # Examples
53
+ #
54
+ # success 'Ok'
55
+ # # => nil
56
+ #
57
+ # Returns nothing.
58
+ def success(message)
59
+ puts message.prepend('➜ ').colorize(:light_green)
60
+ end
61
+
62
+ # Public: Error
63
+ #
64
+ # message - Message.
65
+ #
66
+ # Examples
67
+ #
68
+ # error 'Error'
69
+ # # => nil
70
+ #
71
+ # Returns nothing.
72
+ def error(message)
73
+ puts message.prepend('✗ ').colorize(:light_red)
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,80 @@
1
+ module Speedflow
2
+ # Used to manage the plugins
3
+ class PluginManager
4
+ include ActiveSupport::Inflector
5
+ include Message
6
+
7
+ PLUGIN_BASE = 'speedflow-plugin-'.freeze
8
+
9
+ # Public: Constructor
10
+ #
11
+ # plugins - Array of plugins
12
+ #
13
+ # Examples
14
+ #
15
+ # PluginManager.new({})
16
+ # # => <Speedflow::PluginManager>
17
+ #
18
+ # Returns an Arrays of plugins.
19
+ def initialize(plugins = [])
20
+ @plugins = plugins || []
21
+ load_plugins
22
+ end
23
+
24
+ # Public: Load plugins
25
+ #
26
+ # Returns nothing.
27
+ def load_plugins
28
+ @plugins.each { |plugin| require_plugin(plugin) }
29
+ end
30
+
31
+ # Public: Require a plugins (from Gem)
32
+ #
33
+ # Returns nothing.
34
+ def require_plugin(plugin)
35
+ require plugin.downcase.prepend(PLUGIN_BASE)
36
+ rescue LoadError
37
+ message = "Unable to load plugin '#{plugin}'.\n"
38
+ message << "Help: `gem install #{PLUGIN_BASE}#{plugin}`"
39
+ raise PluginNotFound, message
40
+ end
41
+
42
+ # Call action from flow step.
43
+ #
44
+ # step - Hash from flow. {plugin: '', action: '', arguments: ''}.
45
+ #
46
+ # Returns nothing.
47
+ def call_action_from_step(step)
48
+ step['arguments'] ||= {}
49
+ success "Run action '#{step['action']}' of '#{step['plugin']}' plugin."
50
+ call_plugin_action(step['plugin'], step['action'], step['arguments'])
51
+ end
52
+
53
+ # Call plugin action.
54
+ #
55
+ # plugin - Plugin name.
56
+ # action - Action name.
57
+ # arguments - List of arguments
58
+ #
59
+ # Returns nothing.
60
+ def call_plugin_action(plugin, action, arguments)
61
+ action = underscore(action.prepend('action_'))
62
+ module_name = plugin.downcase.capitalize.prepend('Speedflow::Plugin::')
63
+ begin
64
+ Kernel.const_get(module_name).send(action.to_s, arguments)
65
+ rescue NoMethodError => exception
66
+ message = "Unable to call action: #{module_name}.#{action}\n"
67
+ message << exception.message
68
+ raise PluginActionNotFound, message
69
+ end
70
+ end
71
+ end
72
+
73
+ # Plugin exception
74
+ class PluginNotFound < Exception
75
+ end
76
+
77
+ # Plugin action exception
78
+ class PluginActionNotFound < Exception
79
+ end
80
+ end
@@ -0,0 +1,3 @@
1
+ module Speedflow
2
+ VERSION = '0.1.0'.freeze
3
+ end
data/lib/speedflow.rb ADDED
@@ -0,0 +1,12 @@
1
+ require 'require_all'
2
+ require 'active_support/core_ext/hash'
3
+ require 'active_support/inflector'
4
+ require 'safe_yaml/load'
5
+
6
+ require_rel 'speedflow/*.rb'
7
+ require_rel 'speedflow/core_ext/*.rb'
8
+ require_rel 'speedflow/commands/*.rb'
9
+
10
+ # Speedflow core
11
+ module Speedflow
12
+ end
metadata ADDED
@@ -0,0 +1,229 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: speedflow
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Julien Breux
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-03-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: require_all
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: mercenary
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.3.5
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.3.5
41
+ - !ruby/object:Gem::Dependency
42
+ name: activesupport
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: colorize
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: safe_yaml
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: speedflow-plugin-test
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: bundler
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.11'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.11'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rake
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '10.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '10.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rspec
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '3.0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '3.0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: pry
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: codeclimate-test-reporter
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: simplecov
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ description: Speedflow provides a robust system to transform yourpainful workflow
182
+ in a sweet workflow.
183
+ email:
184
+ - julien.breux@gmail.com
185
+ executables:
186
+ - speedflow
187
+ extensions: []
188
+ extra_rdoc_files: []
189
+ files:
190
+ - LICENSE
191
+ - README.md
192
+ - bin/console
193
+ - bin/setup
194
+ - bin/speedflow
195
+ - lib/speedflow.rb
196
+ - lib/speedflow/command.rb
197
+ - lib/speedflow/commands/flow.rb
198
+ - lib/speedflow/commands/help.rb
199
+ - lib/speedflow/configuration.rb
200
+ - lib/speedflow/core_ext/hash.rb
201
+ - lib/speedflow/flow.rb
202
+ - lib/speedflow/message.rb
203
+ - lib/speedflow/plugin_manager.rb
204
+ - lib/speedflow/version.rb
205
+ homepage: https://github.com/speedflow/speedflow
206
+ licenses:
207
+ - MIT
208
+ metadata: {}
209
+ post_install_message:
210
+ rdoc_options: []
211
+ require_paths:
212
+ - lib
213
+ required_ruby_version: !ruby/object:Gem::Requirement
214
+ requirements:
215
+ - - ">="
216
+ - !ruby/object:Gem::Version
217
+ version: '0'
218
+ required_rubygems_version: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: '0'
223
+ requirements: []
224
+ rubyforge_project:
225
+ rubygems_version: 2.5.2
226
+ signing_key:
227
+ specification_version: 4
228
+ summary: Speedflow is a command-line tool to help you to keep your time.
229
+ test_files: []