Compare commits

...

48 commits

Author SHA1 Message Date
Glenn Y. Rolland a707be5c63 Use the same window, if possible. 2015-07-15 16:21:02 +02:00
Glenn Y. Rolland 06c00e545c Compute column width depending on project names. 2015-07-15 16:20:30 +02:00
Glenn Y. Rolland 798932046a Add more README sections. 2015-07-15 16:20:30 +02:00
Glenn Y. Rolland 8216c91e88 Improve .gitignore. 2015-07-15 16:19:03 +02:00
Glenn Y. Rolland a5dbbb1d49 Remove useless lines. 2015-07-15 16:18:44 +02:00
Glenn Y. Rolland d338b1c924 Add tasks for building gem file. 2015-07-15 16:18:44 +02:00
Glenn Y. Rolland 30f8d5e9a0 Fill license. 2015-07-15 16:18:24 +02:00
Glenn Y. Rolland ddbb2903cb Raise max length for project name. 2015-07-15 16:18:08 +02:00
Glenn Y. Rolland b1c0c2b5ef Added todo list. 2015-07-15 16:18:08 +02:00
Glenn Y. Rolland b750e281ef Cleanup main script (remove bundler ref & unwanted inclusions). 2015-07-15 16:18:08 +02:00
Glenn Y. Rolland d46d6a0fd4 Improve documentation. 2015-07-15 16:17:27 +02:00
Glenn Y. Rolland 03481e6ee4 Add plugin directory structure. 2015-07-15 16:16:33 +02:00
Glenn Y. Rolland fbee330868 Rakefile: Include tasks for Gem. 2014-01-04 11:13:26 +01:00
Glenn Y. Rolland 53d34ddbf1 Added a real README. 2014-01-04 11:11:59 +01:00
Glenn Y. Rolland 1e72d86d54 version: Use a name compatible with Gemspec --pre. 2014-01-04 11:03:58 +01:00
Glenn Y. Rolland f8ce378b99 Remove pry from dependencies. 2014-01-04 11:03:40 +01:00
Glenn Y. Rolland d9edb054ad Add license file. 2014-01-04 11:03:24 +01:00
Glenn Y. Rolland 6886f36c08 Gemfile: Move dependencies to Gemspec. 2014-01-04 11:03:02 +01:00
Glenn Y. Rolland 55d203da8d Improve gitignore for gem release. 2014-01-04 11:02:43 +01:00
Glenn Y. Rolland 470d0b42f8 Improve CLI command descriptions for help. 2014-01-03 10:47:38 +01:00
Glenn Y. Rolland 9f045fb5d9 Reduce view name lenght limit. 2014-01-03 10:41:12 +01:00
Glenn Y. Rolland 2d6d5b21e3 Fix version string (add dev suffix). 2014-01-03 10:41:00 +01:00
Glenn Y. Rolland 58ad2950f8 cli: fix current project detection. 2014-01-03 10:40:48 +01:00
Glenn Y. Rolland 19e6e14f01 cli: Add support for 'firing' projects. 2014-01-03 10:40:13 +01:00
Glenn Y. Rolland 3b0e5a2ce3 bin: Resolve real path (even if linked). 2014-01-03 10:39:14 +01:00
Glenn Y. Rolland 0a23465b98 Add readline dependency if needed. 2014-01-03 10:38:52 +01:00
Glenn Y. Rolland 93be352501 Add a header on Kookfiles. 2014-01-03 09:56:42 +01:00
Glenn Y. Rolland 841cde2dc2 Add version number. 2014-01-03 09:53:12 +01:00
Glenn Y. Rolland f5896f6b2d Continue reimplementing missing features. 2014-01-03 01:35:43 +01:00
Glenn Y. Rolland d3ec76f37a app: fix usage of frozen string & remove trailing slash. 2014-01-03 00:56:50 +01:00
Glenn Y. Rolland 90576fb2b4 Added edition support. 2014-01-03 00:53:49 +01:00
Glenn Y. Rolland 4cb5238065 Move project listing to app. 2014-01-03 00:38:47 +01:00
Glenn Y. Rolland 52731febd5 Added (empty) LICENSE file. 2014-01-03 00:27:18 +01:00
Glenn Y. Rolland def5c85f68 Add dependency upon rspec. 2014-01-03 00:25:36 +01:00
@@@No user configured@@@ c0f0c890ca Prepare for unit tests. 2014-01-02 23:36:35 +01:00
Glenn Y. Rolland cda1edf92c Add basic gitignore. 2013-12-31 00:29:42 +01:00
Glenn Y. Rolland ffa3c6c39e Use Gemfile. 2013-12-31 00:29:07 +01:00
Glenn Y. Rolland f200005e92 Add view creation support. 2013-12-28 15:31:39 +01:00
Glenn Y. Rolland cdcec384f0 Continue ruby implementation. 2013-12-28 15:05:51 +01:00
Glenn Y. Rolland 34b3f80b3e Remove local Kookfile. 2013-12-28 15:05:32 +01:00
Glenn Y. Rolland 93a9772ee3 Ignore local Kookfile. 2013-12-28 15:05:16 +01:00
Glenn Y. Rolland a4d9c5b39b Add more tests. 2013-12-28 15:04:41 +01:00
Glenn Y. Rolland f90bbee818 Rewrite in ruby. 2013-12-28 11:55:48 +01:00
Glenn Y. Rolland 4c4f0e1ddc Prepare for rake tasks. 2013-12-27 12:44:22 +01:00
Glenn Y. Rolland ef6c37e43e Fix new session creation. 2013-12-27 12:43:48 +01:00
Glenn Y. Rolland d6d5e66cfa Added kook script. 2013-12-27 01:56:57 +01:00
@@@No user configured@@@ 488d4616e0 Add name suggestion. 2013-12-26 01:56:30 +01:00
Glenn Y. Rolland a61d466bd1 Fix symbolic link handling & arguments parameters. 2013-06-04 17:02:52 +02:00
24 changed files with 944 additions and 82 deletions

15
.gitignore vendored Normal file
View file

@ -0,0 +1,15 @@
*.a
/.bundle/
/coverage/
/doc/
/Gemfile.lock
/Kookfile
mkmf.log
*.o
/pkg/
*.so
/spec/reports/
/tmp/
/vendor/
/_yardoc/
/.yardoc

4
Gemfile Normal file
View file

@ -0,0 +1,4 @@
# A sample Gemfile
source "https://rubygems.org"
gemspec

22
LICENSE.md Normal file
View file

@ -0,0 +1,22 @@
Copyright (c) 2015 Glenn Y. Rolland
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -1,8 +1,74 @@
KoProj is a tool for managing console project environments
# Kook
Ex: Project X require 3 terminals, with name A, B, C
A : must be in directory ~/
B : must be in directory ~/foo
run command X
C : must be in directory ~/bar
run command Y
Kook is a helper for opening your projects environments in tabs of KDE Konsole.
## Installation
Simply install kook via the 'gem' package manager
$ gem install kook
## Usage
Imagine, that for working on your project, you requires multiple terminal consoles,
with different tools in them.
Let say that :
A : must be in directory ~/src/myProject/
B : must be in directory ~/src/myProject/app
and run command "$EDITOR ."
C : must be in directory ~/src/myProject/log
and run command "tail -f development.log"
Kook aims to prepare your project environment, just like you want it to be,
with all you tabs and the commands inside in the right directories. Everything
in one single command.
## Contributing
1. Fork it ( http://github.com/glenux/kook/fork )
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request
## Alternatives
* Tmuxinator (the same goal, based on tmux instead of Konsole)
# Kook
TODO: Write a gem description
## Installation
Add this line to your application's Gemfile:
```ruby
gem 'kook'
```
And then execute:
$ bundle
Or install it yourself as:
$ gem install kook
## Usage
TODO: Write usage instructions here
## Contributing
1. Fork it ( https://github.com/[my-github-username]/kook/fork )
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create a new Pull Request

7
Rakefile Normal file
View file

@ -0,0 +1,7 @@
require 'rspec/core/rake_task'
require "bundler/gem_tasks"
RSpec::Core::RakeTask.new(:spec)
task :default => :spec

16
TODO.md Normal file
View file

@ -0,0 +1,16 @@
Kook Task List
==============
Package as a gem
-----------------
- ( ) Write gemspec
- ( ) Migrate gems & check versions
Marketing
---------
- ( ) Rename project
- ( ) Write documentation

23
bin/kook Executable file
View file

@ -0,0 +1,23 @@
#!/usr/bin/env ruby
# vim: set syntax=ruby:
require 'yaml'
require 'singleton'
require 'pathname'
require 'colorize'
DATA_DIR = (Pathname.new(__FILE__).dirname + '..').realpath.to_s
require 'thor'
require 'kook'
begin
Kook::CLI::Main.start(ARGV)
rescue Exception => exception
# In case of unhandled exception.
# FIXME: Manage display & create log file
STDERR.puts "ERROR(#{exception.class}) : #{exception}"
STDERR.puts exception.backtrace
exit 1
end

View file

@ -1,51 +0,0 @@
#!/bin/sh
KOTAM_DATA_DIR=$(cd `dirname "$0"`; cd ../lib ; pwd )
KOTAM_CONFIG_DIR=$HOME/.config/kotam
. $KOTAM_DATA_DIR/base.sh
## Expected usage :
#
# kotam exec <name>
# kotam init <name>
#
mkdir -p $KOTAM_CONFIG_DIR
while [ $# -gt 0 ]; do
arg=${1:-}
opt=${2:-}
case $arg in
-l|--list) #list projects
echo "List of projects :"
ls $KOTAM_CONFIG_DIR/*.kotam 2> /dev/null
;;
-e) # edit project
shift
project="$opt"
if [ -z "$project" ]; then
echo "ERROR: project name missing" >&2
exit 1
elif [ ! -e "$KOTAM_CONFIG_DIR/$project.kotam" ]; then
echo "ERROR: unknown project $project" >&2
exit 1
fi
"$EDITOR" "$KOTAM_CONFIG_DIR/$project.kotam"
;;
-c) # create
;;
-d) # destroy
;;
*) #enter into project
project="$arg"
if [ ! -e "$KOTAM_CONFIG_DIR/$project.kotam" ]; then
echo "ERROR: unknown project $project" >&2
exit 1
fi
. "$KOTAM_CONFIG_DIR/$project.kotam"
;;
esac
shift
done

33
kook.gemspec Normal file
View file

@ -0,0 +1,33 @@
# coding: utf-8
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'kook/version'
Gem::Specification.new do |spec|
spec.name = "kook"
spec.version = Kook::VERSION
spec.authors = ["Glenn Y. Rolland"]
spec.email = ["glenux@glenux.net"]
spec.summary = %q{Kook is a helper for opening your projects environments in tabs of KDE Konsole}
#spec.description = %q{TODO: Write a longer description. Optional.}
spec.homepage = "http://github.com/glenux/kook"
spec.license = "MIT"
spec.rubyforge_project = "kook"
spec.files = `git ls-files`.split($/)
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = ["lib"]
spec.bindir = 'bin'
spec.post_install_message = "Thanks for installing!"
spec.add_development_dependency "bundler", "~> 1.5"
spec.add_development_dependency "rake"
spec.add_development_dependency "rspec"
# spec.add_development_dependency "pry"
# spec.add_development_dependency "rm-readline"
spec.add_runtime_dependency "thor"
spec.add_runtime_dependency "colorize"
end

View file

@ -1,24 +0,0 @@
kotam_run() {
local cmd="$*"
qdbus org.kde.konsole /Sessions/${session} sendText "$cmd"
qdbus org.kde.konsole /Sessions/${session} sendText "
"
}
kotam_newtab() {
#dbus-send --session --dest=${KONSOLE_DBUS_SERVICE} --type=method_call \
# --print-reply /konsole/MainWindow_1 org.kde.KMainWindow.activateAction string:"new-tab"
session=$(qdbus org.kde.konsole /Konsole newSession)
}
kotam_renametab() {
#sessionno=$1
tabname=$1
#session="/Sessions/${sessionno}"
#dbus-send --session --dest=${KONSOLE_DBUS_SERVICE} --type=method_call --print-reply ${session} org.kde.konsole.Session.setTitle int32:1 string:"$tabname"
qdbus org.kde.konsole /Sessions/${session} setTitle 1 "$tabname"
}

8
lib/kook.rb Normal file
View file

@ -0,0 +1,8 @@
require 'kook/version'
require 'kook/exceptions'
require 'kook/view'
require 'kook/project'
require 'kook/app'
require 'kook/cli'

203
lib/kook/app.rb Normal file
View file

@ -0,0 +1,203 @@
module Kook
class App
CONFIG_DIR = File.join ENV['HOME'], '.config', 'kook'
CONFIG_FILE = File.join CONFIG_DIR, 'config.yml'
attr_accessor :verbose
class ExistingProject < RuntimeError ; end
class MissingProject < RuntimeError ; end
class MissingProjectFile < RuntimeError ; end
def initialize
super
@projects = {}
@config_file = CONFIG_FILE
@verbose = false
@current_project = nil
end
def list_projects
projects_exist = false
# get boundary for project name + margin
column_width = @projects.map{ |name,data| name }.max
@projects.each do |project_name,project_data|
projects_exist = true
exist = File.exist? project_data.path
display_path = (
project_data.path.clone
.gsub!(/#{ENV['HOME']}/,'~')
.send(exist ? :green : :red)
)
puts "%- #{column_width}s %s" % [project_name, display_path]
end
STDERR.puts "No project found." if not projects_exist
end
def add_project project_name, project_path=nil
raise ExistingProject if @projects.has_key? project_name
project_data = Project.new project_name
project_data.path = project_path
@projects[project_name] = project_data
save
end
def edit_project project_name
raise MissingProject if not @projects.has_key? project_name
project_config_path = File.join @projects[project_name].path, "Kookfile"
system "%s %s" % [ENV['EDITOR'], project_config_path]
end
def remove_project project_name
raise MissingProject if not @projects.has_key? project_name
@projects.delete project_name
save
end
def fire_project project_name
raise MissingProject if not @projects.has_key? project_name
project_path = @projects[project_name].path
@projects[project_name].fire
end
def add_view project_name, view_name, view_path=nil
View.validate_name view_name
raise MissingProject if not @projects.has_key? project_name
project_path = @projects[project_name].path
# simplify if current dir is a subdir of project base
if view_path == project_path then
view_path = '.'
else
view_path = (view_path
.gsub(/^#{project_path}\//,'')
.gsub(/\/$/,'')
)
end
@projects[project_name].create_view view_name, view_path
save
end
def add_command project_name, view_name, command
View.validate_name view_name
raise MissingProject if not @projects.has_key? project_name
@projects[project_name].add_command view_name, command
save
end
def remove_command project_name, view_name, command_idx
raise MissingProject if not @projects.has_key? project_name
@projects[project_name].remove_command view_name, command_idx
save
end
def list_views project_name
raise MissingProject if not @projects.has_key? project_name
@projects[project_name].each_view do |view_name,view_data|
puts "%- 24s %s" % [view_name, view_data.path]
if view_data.commands.empty?
next
end
view_data.commands.each_index do |idx|
puts "* % 4d. %s" % [idx, view_data.commands[idx]]
end
end
end
def load config_file=nil
config_file ||= @config_file
@config_file = config_file
if not File.exist? config_file then
STDERR.puts "Missing config file #{config_file}" if @verbose
return false
end
STDERR.puts "Loading main configuration #{config_file}..." if @verbose
yaml = YAML::load_file config_file
yaml['projects'].each do |project_name,project_path|
# pp project_path
#project_path = @config['projects'][project]
project_file = File.join project_path, "Kookfile"
STDERR.puts "Loading sub configuration #{project_file}..." if @verbose
if File.exist? project_file then
subconfig = YAML::load_file project_file
next if not subconfig
@projects[project_name] = Project.from_hash subconfig, project_path
end
end
return true
end
def save config_file=nil
config_file ||= @config_file
config_dir = File.dirname config_file
if not File.exist? config_dir then
FileUtils.mkdir_p config_dir
end
STDERR.puts "Saving to #{config_file}" if @verbose
@projects.each do |project_name,project_data|
# FIXME: test if project configuration is dirty
project_file = File.join project_data.path, "Kookfile"
File.open(project_file, "w") do |file|
file.puts "# This file was generated by Kook #{VERSION}"
file.puts "# You can get it at https://github.com/glenux/kook"
file.write project_data.to_hash.to_yaml
end
end
File.open(config_file, "w") do |file|
file.write to_yaml
end
self
end
def current_project= project_name
# FIXME: validate project name
@current_project = project_name
end
def current_project
return @current_project if not @current_project.nil?
current_dir = Dir.pwd
@projects.each do |project_name,project|
if current_dir =~ /^#{project.path}/ then
return project_name
end
end
return nil
end
private
def to_yaml
return {
'global' => {},
'projects' => Hash[@projects.map{ |p,v| [v.name, v.path] }]
}.to_yaml
end
end
end

174
lib/kook/cli.rb Normal file
View file

@ -0,0 +1,174 @@
require 'thor'
module Kook
module CLI
module KookHelper
def before_filter options
@app = App.new
@app.load options[:config]
@app.verbose = options[:verbose]
@app.current_project = options[:project]
end
# Inject our extensions in thor instances
def self.included(base)
base.class_eval do
#if ancestors.include? Thor::Group
# namespace self.name.split('::').last.downcase.to_sym
#end
class_option :verbose,
type: :boolean,
default: false,
aliases: '-v',
desc: 'Whether to output informative debug'
class_option :config,
type: :string,
default: nil,
aliases: '-c',
desc: 'Configuration file'
class_option :project,
type: :string,
default: nil,
aliases: '-p',
desc: 'Target project'
class_option :directory,
type: :string,
default: nil,
aliases: '-d',
desc: 'Target directory'
end
end
end
class Project < Thor
include KookHelper
desc "detect", "Detect current project"
def detect
before_filter options
current_project = @app.current_project
project_name = current_project.nil? ? "-none-" : current_project
say "Current project is #{project_name}."
end
desc "list", "List projects"
def list
before_filter options
@app.list_projects
end
desc "add PROJECT [-d DIRECTORY]", "Register new project"
def add project_name
before_filter options
project_path = options[:directory]
if project_path.nil? then
project_path = Dir.pwd
end
project_path = File.expand_path project_path
@app.add_project project_name, project_path
say "Project #{project_name} registered on #{project_path}."
end
desc "rm PROJECT", "Unregister existing project"
def rm project
before_filter options
@app.remove_project project
say "Project #{project} unregistered."
end
desc "edit [-p PROJECT]", "Open editor on project file"
def edit
before_filter options
project_name ||= @app.current_project
@app.edit_project project_name
end
# TODO: editcopy project to another name + base path
# TODO: copy project to another name + base path
end
class View < Thor
include KookHelper
desc "list [-p PROJECT]", "List view for a project"
def list
before_filter options
project_name = @app.current_project
@app.list_views project_name
end
desc "add VIEW [-p PROJECT] [-d DIRECTORY]", "Register new view"
def add view_name
before_filter options
project_name = @app.current_project
view_path = options[:directory]
if view_path.nil? then
view_path = Dir.pwd
end
@app.add_view project_name, view_name, view_path
end
desc "rm VIEW [-p PROJECT]", "Unregister existing view on project"
def rm view_name
before_filter options
project_name = @app.current_project
@app.remove_view project_name, view_name, view_path
end
end
# FIXME: add helper validating project name
# FIXME: add helper validating vie name for project
class Command < Thor
include KookHelper
desc "add VIEW COMMAND [-p PROJECT]", "Add command for view"
def add view_name, command
before_filter options
project_name = @app.current_project
@app.add_command project_name, view_name, command
end
desc "rm VIEW INDEX [-p PROJECT]", "Remove command for view"
def rm view_name, command_index
before_filter options
project_name = @app.current_project
@app.remove_command project_name, view_name, command_index.to_i
end
end
class Main < Thor
include KookHelper
desc "project SUBCOMMAND [options]", "Commands for managing projects"
subcommand "project", CLI::Project
desc "view SUBCOMMAND [options]", "Commands for managing view"
subcommand "view", CLI::View
desc "command SUBCOMMAND [options]", "Commands for managing commands"
subcommand "command", CLI::Command
desc "start [-p PROJECT]", "Run project environment"
def start
before_filter options
project_name = @app.current_project
@app.fire_project project_name
end
end
end
end

4
lib/kook/exceptions.rb Normal file
View file

@ -0,0 +1,4 @@
module Kook
class MissingProjectConfiguration < RuntimeError ; end
end

View file

View file

View file

0
lib/kook/plugins/tmux.rb Normal file
View file

119
lib/kook/project.rb Normal file
View file

@ -0,0 +1,119 @@
require 'kook/exceptions'
module Kook
class Project
attr_reader :name, :path
attr_accessor :description
class MissingProjectFile < RuntimeError ; end
class InvalidProjectName < RuntimeError ; end
PROJECT_NAME_MIN_SIZE = 4
PROJECT_NAME_MAX_SIZE = 15
def initialize project_name
self.class.validate_name project_name
@name = project_name
@description = nil
@path = nil
@views = {}
yield self if block_given?
self
end
def path= path
# FIXME: validate current path exists
#
if not (File.exist? path and File.directory? path) then
raise "PathDoesNotExist #{path}"
end
@path = path
end
def fire
target = ENV['KONSOLE_DBUS_SERVICE'] || 'org.kde.konsole'
window = ENV['KONSOLE_DBUS_WINDOW'] || '/Konsole'
# FIXME: use runCommand instead of sendText ?
@views.each do |view,view_data|
session=`qdbus #{target} #{window} newSession`.strip
system "qdbus org.kde.konsole /Sessions/#{session} sendText \"cd #{@path}\n\""
system "qdbus org.kde.konsole /Sessions/#{session} sendText \"cd #{view_data.path}\n\""
system "qdbus org.kde.konsole /Sessions/#{session} sendText \"clear\n\""
system "qdbus org.kde.konsole /Sessions/#{session} setTitle 1 \"#{view}\""
view_data.commands.each do |command|
system "qdbus org.kde.konsole /Sessions/#{session} sendText \"#{command}\""
system "qdbus org.kde.konsole /Sessions/#{session} sendText \"\n\""
end
end
end
def create_view view_name, view_path
raise ExistingView, view_name if @views.has_key? view_name
View.validate_name view_name
@views[view_name] = View.new view_name, view_path
end
def add_view view_data
raise ExistingView, view_data.name if @views.has_key? view_data.name
@views[view_data.name] = view_data
end
def remove_view view_name
raise MissingView, view_name if not @views.has_key? view_name
return @view.delete(view_name)
end
def add_command view_name, command
raise MissingView, view_name if not @views.has_key? view_name
@views[view_name].commands << command
end
def remove_command view_name, command_idx
raise MissingView, view_name if not @views.has_key? view_name
@views[view_name].commands.delete_at(command_idx)
end
def each_view
#pp @views
@views.each do |view_name, view_data|
yield view_name, view_data
end
end
def to_hash
return {
'project' => @name,
'description' => @description,
#'path' => @path,
'views' => @views.values.map{ |v| v.to_hash }
}
end
def self.from_hash project_hash, project_path
project = Project.new project_hash['project'] do |p|
p.description = project_hash['description']
p.path = project_path
project_hash['views'].each do |view_hash|
view_data = View.from_hash view_hash
p.add_view view_data
end
end
end
def self.validate_name name
raise "TooShortProjectIdentifier" if name.size < Project::PROJECT_NAME_MIN_SIZE
raise "TooLongProjectIdentifier" if name.size > Project::PROJECT_NAME_MAX_SIZE
if not name =~ /^\w(\S+)$/ then
raise "BadProjectIdentifier #{name}"
end
return true
end
end
end

3
lib/kook/version.rb Normal file
View file

@ -0,0 +1,3 @@
module Kook
VERSION = "0.1.0.dev"
end

49
lib/kook/view.rb Normal file
View file

@ -0,0 +1,49 @@
module Kook
class View
attr_reader :name, :path, :commands
attr_accessor :description
VIEW_NAME_MIN_SIZE = 3
VIEW_NAME_MAX_SIZE = 12
def initialize name, path=nil
self.class.validate_name name
@name = name
@path = path
@commands = []
end
def self.validate_name name
raise "TooShortViewIdentifier" if name.size < View::VIEW_NAME_MIN_SIZE
raise "TooLongViewIdentifier" if name.size > View::VIEW_NAME_MAX_SIZE
if not name =~ /^[\w-]+$/ then
raise "BadViewIdentifier #{name}"
end
return true
end
def to_hash
return {
'view' => @name,
'path' => @path,
'commands' => @commands
}
end
def add_command command
@commands << command
end
def rm_command command_index
@command.delete command_index
end
def self.from_hash view_hash
view = View.new view_hash['view'], view_hash['path']
view_hash['commands'].each do |c|
view.add_command c
end
return view
end
end
end

61
spec/spec_helper.rb Normal file
View file

@ -0,0 +1,61 @@
# Load all spec files
Dir["./spec/support/**/*.rb"].each {|f| require f}
RSpec.configure do |config|
# Allows using build(), create(), etc. without the "FactoryGirl." part.
config.include FactoryGirl::Syntax::Methods
config.before(:each) do
$0 = "kook" # Pretend we're running as 'kook'
ARGV.clear # Make sure no args are passed to the commands.
@directory = Dir.mktmpdir('kook-spec-') # Create a temp directory to work in.
@orig_directory = Dir.pwd # Save the original directory.
Dir.chdir(@directory) # Change to it. pwd() is the temp directory in the examples.
end
config.after(:each) do
Dir.chdir(@orig_directory) # Change back to the origin directory.
FileUtils.rmtree(@directory) # Remove the temp directory.
end
# Captures the output for analysis later
#
# @example Capture `$stderr`
#
# output = capture(:stderr) { $stderr.puts "this is captured" }
#
# @param [Symbol] stream `:stdout` or `:stderr`
# @yield The block to capture stdout/stderr for.
# @return [String] The contents of $stdout or $stderr
def capture(stream)
begin
stream = stream.to_s
eval "$#{stream} = StringIO.new"
yield
result = eval("$#{stream}").string
ensure
eval("$#{stream} = #{stream.upcase}")
end
result
end
# Silences the output stream
#
# @example Silence `$stdout`
#
# silence(:stdout) { $stdout.puts "hi" }
#
# @param [IO] stream The stream to use such as $stderr or $stdout
# @return [nil]
alias :silence :capture
end
EXAMPLES_DIR = Pathname.new(__FILE__).dirname + 'examples'

60
spec/test_project.rb Executable file
View file

@ -0,0 +1,60 @@
#!/usr/bin/env ruby
require 'singleton'
require 'yaml'
require 'pp'
module Kook
class Config
include Singleton
def create_project project_name
raise "ExistingProject" if @projects.has_key? project_name
@projects[project_name] = Project.new project_name
end
def create_view project_name, view_name
Project.validate_name project_name
View.validate_name view_name
raise "MissingProject" if not @projects.has_key? project_name
view = View.new view_name
@projects[project_name].add_view view
end
def to_yaml
return {
global: {},
projects: @projects.values.map{ |p| p.to_hash }
}.to_yaml
end
private
def initialize
@projects = {}
super
end
end
end
class Test
def self.test_project_create
config = Kook::Config.instance
config.create_project 'proj'
end
def self.test_view_create
config = Kook::Config.instance
config.create_view 'proj', 'proj-root'
config.create_view 'proj', 'proj-base'
config.create_view 'proj', 'proj-3'
puts config.to_yaml
end
end
Test.test_project_create
Test.test_view_create

70
test.sh Executable file
View file

@ -0,0 +1,70 @@
#!/bin/sh
PATH=./bin:$PATH
set -e
KOOK_TEST_CONFIG="$(pwd)/test.config.yml"
KOOK_OPTS="--verbose --config $KOOK_TEST_CONFIG"
TEST_TITLE=""
fail() {
echo "ERROR: $TEST_TITLE"
exit 1
}
test_cleanup() {
rm -f $KOOK_TEST_CONFIG
rm -f Kookfile
}
test_start() {
test_cleanup
TEST_TITLE="$*"
echo ""
echo ""
echo "## TEST : $TEST_TITLE"
echo ""
}
test_start "Simple project listing"
kook project list $KOOK_OPTS || fail
test_start "Add project (explicit pah)"
kook project add kook-project $KOOK_OPTS --path . || fail
kook project list $KOOK_OPTS || fail
test_start "Add project (auto path)"
kook project add kook-project $KOOK_OPTS || fail
kook project list $KOOK_OPTS || fail
test_start "Add and remove project"
kook project add kook-project $KOOK_OPTS || fail
kook project list $KOOK_OPTS || fail
kook project rm kook-project $KOOK_OPTS || fail
kook project list $KOOK_OPTS || fail
test_start "Detect current project"
kook project add kook-project $KOOK_OPTS || fail
kook project list $KOOK_OPTS || fail
kook project detect $KOOK_OPTS || fail
test_start "Simple view listing (explicit project)"
kook project add kook-project $KOOK_OPTS || fail
kook view list $KOOK_OPTS --project kook-project || fail
#test_start "Simple view listing (implicit project)"
#kook project add kook-project $KOOK_OPTS || fail
#kook view list $KOOK_OPTS || fail
test_start "Fire a project with no view"
kook project add kook-project $KOOK_OPTS || fail
kook view list $KOOK_OPTS || fail
kook fire kook-project $KOOK_OPTS || fail
test_start "Add a project with a view (explicit project)"
kook project add kook-project $KOOK_OPTS || fail
kook view add root $KOOK_OPTS --project kook-project || fail
kook view list $KOOK_OPTS --project kook-project || fail
#test_cleanup