automux 0.0.1

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 (71) hide show
  1. data/.gitignore +5 -0
  2. data/Gemfile +6 -0
  3. data/Gemfile.lock +20 -0
  4. data/LICENSE.txt +22 -0
  5. data/VERSION +1 -0
  6. data/automux.gemspec +18 -0
  7. data/bin/automux +22 -0
  8. data/data/automux/blueprints/default.yml +26 -0
  9. data/data/automux/recipes/default.sh.erb +46 -0
  10. data/features/custom_recipes.feature +63 -0
  11. data/features/error_messages.feature +8 -0
  12. data/features/general_usage.feature +180 -0
  13. data/features/managing_blueprints.feature +66 -0
  14. data/features/runtime_options.feature +84 -0
  15. data/features/session_and_window_options.feature +67 -0
  16. data/features/session_hooks.feature +68 -0
  17. data/features/setup_windows.feature +22 -0
  18. data/features/step_definitions/custom_recipes_steps.rb +9 -0
  19. data/features/step_definitions/managing_blueprints_steps.rb +9 -0
  20. data/features/step_definitions/setup_windows_steps.rb +18 -0
  21. data/features/step_definitions/shared_steps.rb +43 -0
  22. data/features/support/env.rb +8 -0
  23. data/features/support/hooks.rb +4 -0
  24. data/features/support/transformations.rb +6 -0
  25. data/lib/automux.rb +9 -0
  26. data/lib/automux/cache.rb +10 -0
  27. data/lib/automux/cache/blueprint.rb +20 -0
  28. data/lib/automux/cache/recipe.rb +27 -0
  29. data/lib/automux/controller.rb +14 -0
  30. data/lib/automux/controller/base.rb +18 -0
  31. data/lib/automux/controller/blueprints.rb +45 -0
  32. data/lib/automux/controller/messages.rb +11 -0
  33. data/lib/automux/controller/recipes.rb +39 -0
  34. data/lib/automux/controller/setup.rb +11 -0
  35. data/lib/automux/controller/support.rb +5 -0
  36. data/lib/automux/controller/support/filters.rb +55 -0
  37. data/lib/automux/controller/support/rendering.rb +54 -0
  38. data/lib/automux/core.rb +11 -0
  39. data/lib/automux/core/base.rb +7 -0
  40. data/lib/automux/core/blueprint.rb +31 -0
  41. data/lib/automux/core/error.rb +15 -0
  42. data/lib/automux/core/hook.rb +26 -0
  43. data/lib/automux/core/option.rb +20 -0
  44. data/lib/automux/core/recipe.rb +12 -0
  45. data/lib/automux/core/support.rb +6 -0
  46. data/lib/automux/core/support/custom_accessors.rb +15 -0
  47. data/lib/automux/core/support/hooks_helper.rb +28 -0
  48. data/lib/automux/core/support/options_helper.rb +18 -0
  49. data/lib/automux/core/tmux.rb +6 -0
  50. data/lib/automux/core/tmux/pane.rb +19 -0
  51. data/lib/automux/core/tmux/session.rb +137 -0
  52. data/lib/automux/core/tmux/window.rb +76 -0
  53. data/lib/automux/initializers.rb +2 -0
  54. data/lib/automux/initializers/custom_hooks.rb +4 -0
  55. data/lib/automux/initializers/setup_caches.rb +3 -0
  56. data/lib/automux/library.rb +5 -0
  57. data/lib/automux/library/mini_erb.rb +22 -0
  58. data/lib/automux/library/yaml_parser.rb +41 -0
  59. data/lib/automux/paths.rb +41 -0
  60. data/lib/automux/setup.rb +0 -0
  61. data/lib/automux/views/blueprints/copy.sh.erb +2 -0
  62. data/lib/automux/views/blueprints/create.sh.erb +2 -0
  63. data/lib/automux/views/blueprints/edit.sh.erb +1 -0
  64. data/lib/automux/views/messages/error.sh.erb +3 -0
  65. data/lib/automux/views/setup/clone_defaults.sh.erb +21 -0
  66. data/test/session_test.rb +16 -0
  67. data/test/support/common_methods.rb +0 -0
  68. data/test/support/factories.rb +13 -0
  69. data/test/support/hash_factory.rb +19 -0
  70. data/test/support/test_helper.rb +7 -0
  71. metadata +136 -0
@@ -0,0 +1,45 @@
1
+ module Automux
2
+ module Controller
3
+ class Blueprints < Base
4
+ before_filter :load_blueprint, only: [:edit, :copy, :cp, :delete, :rm]
5
+
6
+ # blueprint_name.yml will be searched under $HOME/.automux/blueprints
7
+ # $ automux blueprint edit blueprint_name
8
+ def edit
9
+ @binding = @blueprint.get_binding
10
+ render 'edit'
11
+ end
12
+
13
+ # This copies the content from default.yml and opens the new file using $EDITOR
14
+ # $ automux blueprint create new_blueprint_name
15
+ def create
16
+ blueprint = Automux::Core::Blueprint.build_by_name(params[:name])
17
+ blueprint.source = Automux::Cache::Blueprint.find_by_name('default')
18
+ @binding = blueprint.get_binding
19
+ render 'create'
20
+ end
21
+
22
+ # $ automux blueprint copy source destination
23
+ def copy
24
+ clone_blueprint = Automux::Core::Blueprint.build_by_name(params[:clone_name])
25
+ clone_blueprint.source = @blueprint
26
+ @binding = clone_blueprint.get_binding
27
+ render 'copy'
28
+ end
29
+ alias_method :cp, :copy
30
+
31
+ # $ automux blueprint delete some_blueprint
32
+ def delete
33
+ @binding = @blueprint.get_binding
34
+ render 'delete'
35
+ end
36
+ alias_method :rm, :delete
37
+
38
+ private ###
39
+
40
+ def load_blueprint
41
+ @blueprint = Automux::Cache::Blueprint.find_by_name(params[:name])
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,11 @@
1
+ module Automux
2
+ module Controller
3
+ class Messages < Base
4
+ def error
5
+ error = Automux::Core::Error.new(params[:message])
6
+ @binding = error.get_binding
7
+ render 'error'
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,39 @@
1
+ module Automux
2
+ module Controller
3
+ class Recipes < Base
4
+ before_filter :load_recipe, only: :automate
5
+ before_filter :load_blueprint, only: :automate
6
+ before_filter :check_blueprint, only: :automate
7
+ before_filter :check_recipe, only: :automate
8
+ before_filter :load_and_setup_session, only: :automate
9
+
10
+ def automate
11
+ @binding = @session.get_binding
12
+ render @recipe.path
13
+ end
14
+
15
+ private ###
16
+
17
+ def load_recipe
18
+ @recipe = Automux::Cache::Recipe.find_by_name(params[:recipe_name])
19
+ end
20
+
21
+ def load_blueprint
22
+ @blueprint = Automux::Cache::Blueprint.find_by_name(params[:blueprint_name])
23
+ end
24
+
25
+ def check_blueprint
26
+ notify_error "Unable to find blueprint named #{ params[:blueprint_name] }.yml" if @blueprint.nil?
27
+ end
28
+
29
+ def check_recipe
30
+ notify_error "Unable to find recipe named #{ params[:recipe_name] }.sh.erb" if @recipe.nil?
31
+ end
32
+
33
+ def load_and_setup_session
34
+ @session = Automux::Core::Tmux::Session.new(@blueprint.read)
35
+ @session.setup
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,11 @@
1
+ module Automux
2
+ module Controller
3
+ class Setup < Base
4
+
5
+ def clone_defaults
6
+ @binding = binding
7
+ render 'clone_defaults'
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ require 'automux/controller/support/filters'
2
+ require 'automux/controller/support/rendering'
3
+
4
+ module Automux::Controller::Support
5
+ end
@@ -0,0 +1,55 @@
1
+ module Automux
2
+ module Controller
3
+ module Support
4
+ module Filters
5
+ attr_reader :filters
6
+ private :filters
7
+
8
+ # Filters is included in the Base controller and all the following methods are intended for its subclasses.
9
+ def inherited(base)
10
+ base.instance_variable_set '@filters', {}
11
+ end
12
+
13
+ # before_filter does not define its logic right away.
14
+ def before_filter(filter_name, options)
15
+ [options[:only]].flatten.each do |action|
16
+ add_filter(filter_name, action)
17
+ end
18
+ end
19
+
20
+ # This is a custom hook intended to run after the subclass definition is read.
21
+ # This helps in calling the before_filter at the top but defining its logic later.
22
+ # See: automux/initializers/custom_hooks.rb for invocation.
23
+ def after_inherited(base)
24
+ # E.g. filters = { automate: [:load_recipe, :load_session], edit: [:load_recipe] }
25
+ base.class_eval do
26
+ # |automate, [:load_recipe, :load_session]|
27
+ filters.each_pair do |name, filter_list|
28
+
29
+ # def automate_with_filters
30
+ # load_recipe
31
+ # load_session
32
+ # automate_without_filters
33
+ # end
34
+ define_method "#{ name }_with_filters" do
35
+ filter_list.each { |filter_name| send(filter_name) }
36
+ send("#{ name }_without_filters")
37
+ end
38
+
39
+ # alias_method_chain automate, filters
40
+ alias_method "#{ name }_without_filters", name
41
+ alias_method name, "#{ name }_with_filters"
42
+ end
43
+ end
44
+ end
45
+
46
+ private ###
47
+
48
+ def add_filter(filter_name, action)
49
+ filters[action] ||= []
50
+ filters[action] << filter_name
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,54 @@
1
+ module Automux
2
+ module Controller
3
+ module Support
4
+ module Rendering
5
+
6
+ # There are two requirements to render a file.
7
+ # 1. @binding
8
+ # 2. file_name
9
+ def render(view)
10
+ path =
11
+ # If the full path to the file is given, use that instead.
12
+ if FileTest.exists?(view)
13
+ view
14
+ else
15
+ deduce_full_path(view)
16
+ end
17
+
18
+ execute Automux::Library::MiniErb.new(File.read(path)).result(@binding)
19
+ end
20
+
21
+ private ###
22
+
23
+ # The full file path will be deduced using current controller name.
24
+ # So for Blueprints, the file will be searched under $HOME/.automux/blueprints.
25
+ # The file will be a bash script with erb support. Hence the need of a @binding object.
26
+ def deduce_full_path(view)
27
+ views_folder_name = demodulize(self.class.name).downcase
28
+ File.join(Paths.root, Paths.views, views_folder_name, "#{ view }.sh.erb")
29
+ end
30
+
31
+ def execute(result)
32
+ modified_result = remove_empty_lines(result)
33
+
34
+ if ENV['AUTOMUX_ENV'] == 'test'
35
+ File.open('/tmp/results', 'w') { |f| f.write(modified_result) }
36
+ exit
37
+ else
38
+ exec(modified_result)
39
+ end
40
+ end
41
+
42
+ # The recipe files can have empty lines for clarity. Remove them here.
43
+ def remove_empty_lines(string)
44
+ string.split("\n").reject { |text| text.strip.empty? }.join("\n")
45
+ end
46
+
47
+ # Remove all parent namespacing.
48
+ def demodulize(class_name)
49
+ class_name.split('::').last
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,11 @@
1
+ require 'automux/core/support'
2
+ require 'automux/core/base'
3
+ require 'automux/core/hook'
4
+ require 'automux/core/option'
5
+ require 'automux/core/tmux'
6
+ require 'automux/core/recipe'
7
+ require 'automux/core/blueprint'
8
+ require 'automux/core/error'
9
+
10
+ module Automux::Core
11
+ end
@@ -0,0 +1,7 @@
1
+ module Automux
2
+ module Core
3
+ class Base
4
+ extend Automux::Core::Support::CustomAccessors
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,31 @@
1
+ module Automux
2
+ module Core
3
+ class Blueprint < Base
4
+ attr_reader :name, :path, :source_blueprint
5
+
6
+ def initialize(path)
7
+ @name = File.basename(path, '.yml')
8
+ @path = path
9
+ end
10
+
11
+ def read
12
+ Automux::Library::YamlParser.load_file(path)
13
+ end
14
+
15
+ def get_binding
16
+ binding
17
+ end
18
+
19
+ def source=(blueprint)
20
+ @source_blueprint = blueprint
21
+ end
22
+
23
+ class << self
24
+ def build_by_name(name)
25
+ path = File.join(Automux::Paths.blueprints_container, "#{ name }.yml")
26
+ new(path)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,15 @@
1
+ module Automux
2
+ module Core
3
+ class Error
4
+ attr_reader :message
5
+
6
+ def initialize(message)
7
+ @message = message
8
+ end
9
+
10
+ def get_binding
11
+ binding
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ require 'erb'
2
+
3
+ module Automux
4
+ module Core
5
+ class Hook
6
+ PRE = 2
7
+ POST = 4
8
+
9
+ attr_reader :command, :type
10
+ private :type
11
+
12
+ def initialize(target, type, command)
13
+ @type = self.class.const_get(type.upcase)
14
+ @command = ERB.new(command).result(target.get_binding)
15
+ end
16
+
17
+ def pre?
18
+ type == PRE
19
+ end
20
+
21
+ def post?
22
+ type == POST
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,20 @@
1
+ module Automux
2
+ module Core
3
+ class Option
4
+ attr_reader :name, :value
5
+
6
+ BOOLEAN_DICTIONARY = { 'true' => :on, 'false' => :off }
7
+
8
+ def initialize(name, value)
9
+ @name = name
10
+ @value = translate_booleans(value)
11
+ end
12
+
13
+ private ###
14
+
15
+ def translate_booleans(value)
16
+ value.to_s.gsub(/(true|false)/, BOOLEAN_DICTIONARY)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,12 @@
1
+ module Automux
2
+ module Core
3
+ class Recipe < Base
4
+ attr_reader :name, :path
5
+
6
+ def initialize(path)
7
+ @name = File.basename(path, '.sh.erb')
8
+ @path = path
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,6 @@
1
+ require 'automux/core/support/custom_accessors'
2
+ require 'automux/core/support/hooks_helper'
3
+ require 'automux/core/support/options_helper'
4
+
5
+ module Automux::Core::Support
6
+ end
@@ -0,0 +1,15 @@
1
+ module Automux
2
+ module Core
3
+ module Support
4
+ module CustomAccessors
5
+ def dup_attr_reader(*names)
6
+ names.each do |name|
7
+ define_method name do
8
+ instance_variable_get("@#{ name }").dup
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,28 @@
1
+ module Automux
2
+ module Core
3
+ module Support
4
+ module HooksHelper
5
+ attr_reader :data_hooks
6
+ private :data_hooks
7
+
8
+ def pre_hooks
9
+ hooks.select(&:pre?)
10
+ end
11
+
12
+ def post_hooks
13
+ hooks.select(&:post?)
14
+ end
15
+
16
+ private ###
17
+
18
+ def setup_hooks
19
+ data_hooks.each do |type, commands|
20
+ [commands].flatten.each do |command|
21
+ @hooks << Hook.new(self, type, command)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,18 @@
1
+ module Automux
2
+ module Core
3
+ module Support
4
+ module OptionsHelper
5
+ attr_reader :data_options
6
+ private :data_options
7
+
8
+ private ###
9
+
10
+ def setup_options
11
+ data_options.each do |name, value|
12
+ @options << Automux::Core::Option.new(name, value)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,6 @@
1
+ require 'automux/core/tmux/session'
2
+ require 'automux/core/tmux/window'
3
+ require 'automux/core/tmux/pane'
4
+
5
+ module Automux::Core::Tmux
6
+ end