auto 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,18 @@
1
+ Copyright (c) 2009 Winton Welsh
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7
+ the Software, and to permit persons to whom the Software is furnished to do so,
8
+ subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,35 @@
1
+ Automaton
2
+ =========
3
+
4
+ Automate everything!
5
+
6
+ Notice
7
+ ------
8
+
9
+ This gem is in development. Functionality updates will show up in this file.
10
+
11
+ Goals
12
+ -----
13
+
14
+ * Writing automation scripts should be simple
15
+ * Global namespace
16
+ * A library of simple methods that do complex things
17
+ * Adding outside scripts and script functionality should be simple
18
+ * Obvious plugin structure
19
+ * Automated installation/updates
20
+ * Running tasks should be simple
21
+ * Everything available via "auto task" command
22
+ * Easy to ask questions
23
+ * Sessions
24
+ * Record input for any number of questions
25
+ * Replay using "auto session" command
26
+ * Or, use the web interface
27
+ * Make it easy for novices to use and extend
28
+
29
+ Install
30
+ -------
31
+
32
+ <pre>
33
+ gem sources -a http://gems.github.com
34
+ sudo gem install winton-automaton
35
+ </pre>
@@ -0,0 +1,49 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/gempackagetask'
4
+ require 'spec/rake/spectask'
5
+
6
+ GEM_NAME = 'automaton'
7
+ PKG_FILES = FileList['**/*'] - FileList['coverage', 'coverage/**/*', 'pkg', 'pkg/**/*']
8
+
9
+ spec = Gem::Specification.new do |s|
10
+ s.author = "Winton Welsh"
11
+ s.email = "mail@wintoni.us"
12
+ s.extra_rdoc_files = [ "README.markdown" ]
13
+ s.files = PKG_FILES.to_a
14
+ s.has_rdoc = false
15
+ s.homepage = "http://github.com/winton/#{GEM_NAME}"
16
+ s.name = 'auto'
17
+ s.platform = Gem::Platform::RUBY
18
+ s.require_path = "lib"
19
+ s.summary = "Automate everything!"
20
+ s.version = "0.1.0"
21
+ end
22
+
23
+
24
+ desc "Package gem"
25
+ Rake::GemPackageTask.new(spec) do |pkg|
26
+ pkg.gem_spec = spec
27
+ end
28
+
29
+ desc "Install gem"
30
+ task :install do
31
+ Rake::Task['gem'].invoke
32
+ `sudo gem uninstall #{GEM_NAME} -x`
33
+ `sudo gem install pkg/#{GEM_NAME}*.gem`
34
+ `rm -Rf pkg`
35
+ end
36
+
37
+ desc "Generate gemspec"
38
+ task :gemspec do
39
+ File.open("#{File.dirname(__FILE__)}/#{GEM_NAME}.gemspec", 'w') do |f|
40
+ f.write(spec.to_ruby)
41
+ end
42
+ end
43
+
44
+ desc "Run specs"
45
+ Spec::Rake::SpecTask.new do |t|
46
+ t.rcov = true
47
+ t.spec_opts = ["--format", "specdoc", "--colour"]
48
+ t.spec_files = FileList["spec/**/*_spec.rb"]
49
+ end
@@ -0,0 +1,6 @@
1
+ automaton-questions:
2
+ repo: git@github.com:winton/automaton-questions.git
3
+ path: vendor/plugins
4
+ automaton-terminal:
5
+ repo: git@github.com:winton/automaton-terminal.git
6
+ path: vendor/plugins
@@ -0,0 +1,8 @@
1
+ require File.dirname(__FILE__) + "/automaton/require"
2
+
3
+ module Automaton
4
+ Runner.new do
5
+ terminal($0)
6
+ end
7
+ exit
8
+ end
@@ -0,0 +1,44 @@
1
+ class Module
2
+
3
+ # Encapsulates the common pattern of:
4
+ #
5
+ # alias_method :foo_without_feature, :foo
6
+ # alias_method :foo, :foo_with_feature
7
+ #
8
+ # With this, you simply do:
9
+ #
10
+ # alias_method_chain :foo, :feature
11
+ #
12
+ # And both aliases are set up for you.
13
+ #
14
+ # Query and bang methods (foo?, foo!) keep the same punctuation:
15
+ #
16
+ # alias_method_chain :foo?, :feature
17
+ #
18
+ # is equivalent to
19
+ #
20
+ # alias_method :foo_without_feature?, :foo?
21
+ # alias_method :foo?, :foo_with_feature?
22
+ #
23
+ # so you can safely chain foo, foo?, and foo! with the same feature.
24
+ def alias_method_chain(target, feature)
25
+ # Strip out punctuation on predicates or bang methods since
26
+ # e.g. target?_without_feature is not a valid method name.
27
+ aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
28
+ yield(aliased_target, punctuation) if block_given?
29
+
30
+ with_method, without_method = "#{aliased_target}_with_#{feature}#{punctuation}", "#{aliased_target}_without_#{feature}#{punctuation}"
31
+
32
+ alias_method without_method, target
33
+ alias_method target, with_method
34
+
35
+ case
36
+ when public_method_defined?(without_method)
37
+ public target
38
+ when protected_method_defined?(without_method)
39
+ protected target
40
+ when private_method_defined?(without_method)
41
+ private target
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,46 @@
1
+ class Class
2
+
3
+ def cattr_reader(*syms)
4
+ syms.flatten.each do |sym|
5
+ next if sym.is_a?(Hash)
6
+ class_eval(<<-EOS, __FILE__, __LINE__)
7
+ unless defined? @@#{sym} # unless defined? @@hair_colors
8
+ @@#{sym} = nil # @@hair_colors = nil
9
+ end # end
10
+ #
11
+ def self.#{sym} # def self.hair_colors
12
+ @@#{sym} # @@hair_colors
13
+ end # end
14
+ #
15
+ def #{sym} # def hair_colors
16
+ @@#{sym} # @@hair_colors
17
+ end # end
18
+ EOS
19
+ end
20
+ end
21
+
22
+ def cattr_writer(*syms)
23
+ syms.flatten.each do |sym|
24
+ class_eval(<<-EOS, __FILE__, __LINE__)
25
+ unless defined? @@#{sym} # unless defined? @@hair_colors
26
+ @@#{sym} = nil # @@hair_colors = nil
27
+ end # end
28
+ #
29
+ def self.#{sym}=(obj) # def self.hair_colors=(obj)
30
+ @@#{sym} = obj # @@hair_colors = obj
31
+ end # end
32
+ #
33
+ #{" #
34
+ def #{sym}=(obj) # def hair_colors=(obj)
35
+ @@#{sym} = obj # @@hair_colors = obj
36
+ end # end
37
+ "}
38
+ EOS
39
+ end
40
+ end
41
+
42
+ def cattr_accessor(*syms)
43
+ cattr_reader(*syms)
44
+ cattr_writer(*syms)
45
+ end
46
+ end
@@ -0,0 +1,108 @@
1
+ require 'rubygems'
2
+
3
+ module Automaton
4
+ class Plugins
5
+
6
+ @@directories = [
7
+ Gem.dir + "/gems",
8
+ "~/.auto",
9
+ "#{File.dirname(__FILE__)}/../../vendor/plugins"
10
+ ]
11
+ @@plugins = nil
12
+
13
+ cattr_accessor :directories
14
+
15
+ class <<self
16
+
17
+ # Add a directory to the plugin load paths.
18
+ def add(path)
19
+ @@directories = [] if $TESTING
20
+ @@directories << path
21
+ @@directories.uniq!
22
+ @@plugins = nil
23
+ end
24
+
25
+ # Returns an array of Plugin instances.
26
+ def plugins
27
+ return @@plugins if @@plugins
28
+ directories = @@directories.collect do |d|
29
+ File.expand_path("#{d}/*automaton-*/")
30
+ end
31
+ @@plugins = Dir[*directories].collect do |d|
32
+ Plugin.new(d)
33
+ end
34
+ @@plugins.compact!
35
+ @@plugins
36
+ end
37
+
38
+ # Returns an array of library file paths.
39
+ def libraries
40
+ collector { |plugin| plugin.library }
41
+ end
42
+
43
+ # Returns an array of modules.
44
+ def modules
45
+ collector { |plugin| plugin.module }
46
+ end
47
+
48
+ # Returns a sorted array of hashes that describe tasks.
49
+ # Returns a specific task with an optional task parameter (string, 'task:name').
50
+ def tasks(task=nil)
51
+ if task
52
+ tasks.select { |t| t[:name] == task.downcase }.first
53
+ else
54
+ t = collector { |plugin| plugin.tasks }
55
+ t = t.flatten
56
+ t.sort do |a, b|
57
+ a[:name].gsub(':', '0') <=> b[:name].gsub(':', '0')
58
+ end
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ # A quick way to get an array of @@plugins attributes.
65
+ def collector(&block)
66
+ self.plugins.collect { |plugin| block.call(plugin) }.compact
67
+ end
68
+ end
69
+
70
+ # Stores a plugin's name, library, and tasks.
71
+ class Plugin
72
+
73
+ attr_reader :name
74
+ attr_reader :library
75
+ attr_reader :module
76
+ attr_reader :tasks
77
+
78
+ # Assigns attributes using a plugin directory path.
79
+ def initialize(directory)
80
+ name = File.basename(directory)
81
+ name = name.split('-')
82
+
83
+ return nil unless name.include?('automaton')
84
+ @name = name[name.index('automaton') + 1]
85
+
86
+ # ~/.auto/automaton-plugin/lib/plugin.rb
87
+ @library = "#{directory}/lib/#{@name}.rb"
88
+ @library = nil unless File.exists?(@library)
89
+
90
+ # Automaton::Plugin
91
+ if @library
92
+ @module = File.basename(@library, '.rb').camelize
93
+ else
94
+ @module = nil
95
+ end
96
+
97
+ # ~/.auto/automaton-plugin/auto/task.rb
98
+ @tasks = Dir["#{directory}/auto/**/*.rb"].sort.collect do |path|
99
+ relative = path.gsub("#{directory}/auto/", '')
100
+ {
101
+ :name => relative[0..-4].split('/').join(':').downcase,
102
+ :path => path
103
+ }
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,8 @@
1
+ # By default, <tt>require 'automaton'</tt> uses Runner to re-evaluate the script.
2
+ # If you don't want the environment (just the classes), require this file.
3
+
4
+ require File.dirname(__FILE__) + "/alias"
5
+ require File.dirname(__FILE__) + "/class"
6
+ require File.dirname(__FILE__) + "/plugins"
7
+ require File.dirname(__FILE__) + "/runner"
8
+ require File.dirname(__FILE__) + "/string"
@@ -0,0 +1,38 @@
1
+ module Automaton
2
+ class Runner
3
+
4
+ def initialize(path_or_task=nil, &block)
5
+ self.class.require!
6
+ run(path_or_task, &block)
7
+ end
8
+
9
+ def run(path_or_task=nil, &block)
10
+ self.instance_eval(&block) if block
11
+ if path_or_task
12
+ task = Plugins.tasks(path_or_task)
13
+ if task
14
+ @path = task[:path]
15
+ elsif File.exists?(path_or_task)
16
+ @path = path_or_task
17
+ end
18
+ self.instance_eval(File.read(@path), @path) if @path
19
+ end
20
+ self
21
+ end
22
+
23
+ class <<self
24
+
25
+ def require!
26
+ Plugins.plugins.each do |plugin|
27
+ if plugin.library
28
+ require plugin.library
29
+ end
30
+ begin
31
+ include eval(plugin.module)
32
+ rescue
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,12 @@
1
+ class String
2
+
3
+ def camelize
4
+ lower_case_and_underscored_word = self
5
+ first_letter_in_uppercase = true
6
+ if first_letter_in_uppercase
7
+ lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
8
+ else
9
+ lower_case_and_underscored_word.first.downcase + lower_case_and_underscored_word.camelize[1..-1]
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,44 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+
3
+ module Automaton
4
+ describe Automaton::Plugins do
5
+
6
+ before(:all) do
7
+ Plugins.add @fixtures = "#{SPEC}/plugins"
8
+ @libraries = Plugins.libraries
9
+ @modules = Plugins.modules
10
+ @tasks = Plugins.tasks
11
+ # debug @libraries
12
+ # debug @modules
13
+ # debug @tasks
14
+ end
15
+
16
+ it "should provide an array of plugin library files" do
17
+ @libraries.should == [
18
+ "#{@fixtures}/automaton-plugin2/lib/plugin2.rb",
19
+ "#{@fixtures}/user-automaton-plugin-0.0.0/lib/plugin.rb"
20
+ ]
21
+ end
22
+
23
+ it "should provide an array of module strings" do
24
+ @modules.should == [ 'Plugin2', 'Plugin' ]
25
+ end
26
+
27
+ it "should provide a hash of plugin task information" do
28
+ @tasks.should == [
29
+ {
30
+ :path => "#{@fixtures}/user-automaton-plugin-0.0.0/auto/plugin/task.rb",
31
+ :name => "plugin:task"
32
+ },
33
+ {
34
+ :path => "#{@fixtures}/automaton-plugin2/auto/plugin2/task.rb",
35
+ :name => "plugin2:task"
36
+ },
37
+ {
38
+ :path => "#{@fixtures}/automaton-plugin2/auto/plugin2/task2.rb",
39
+ :name => "plugin2:task2"
40
+ }
41
+ ]
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,21 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+
3
+ module Automaton
4
+ describe Automaton::Runner do
5
+
6
+ before(:all) do
7
+ Plugins.add @fixtures = "#{SPEC}/plugins"
8
+ @runner = Runner.new
9
+ end
10
+
11
+ it 'should require plugin library files' do
12
+ $".include?("#{@fixtures}/user-automaton-plugin-0.0.0/lib/plugin.rb").should == true
13
+ $".include?("#{@fixtures}/automaton-plugin2/lib/plugin2.rb").should == true
14
+ end
15
+
16
+ it 'should include all plugin library modules' do
17
+ @runner.public_methods.include?('plugin').should == true
18
+ @runner.public_methods.include?('plugin2').should == true
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,7 @@
1
+ module Automaton
2
+ module Plugin2
3
+ def plugin2
4
+ true
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Automaton
2
+ module Plugin
3
+ def plugin
4
+ true
5
+ end
6
+ end
7
+ end
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,15 @@
1
+ $TESTING=true
2
+ SPEC = File.dirname(__FILE__)
3
+ $:.unshift File.expand_path("#{SPEC}/../lib")
4
+
5
+ require 'automaton/require'
6
+ require 'pp'
7
+
8
+ Spec::Runner.configure do |config|
9
+ end
10
+
11
+ def debug(object)
12
+ puts "<pre>"
13
+ puts object.pretty_inspect.gsub('<', '&lt;').gsub('>', '&gt;')
14
+ puts "</pre>"
15
+ end
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: auto
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Winton Welsh
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-11-06 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: mail@wintoni.us
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.markdown
24
+ files:
25
+ - config/externals.yml
26
+ - lib/automaton/alias.rb
27
+ - lib/automaton/class.rb
28
+ - lib/automaton/plugins.rb
29
+ - lib/automaton/require.rb
30
+ - lib/automaton/runner.rb
31
+ - lib/automaton/string.rb
32
+ - lib/automaton.rb
33
+ - MIT-LICENSE
34
+ - Rakefile
35
+ - README.markdown
36
+ - spec/automaton/plugins_spec.rb
37
+ - spec/automaton/runner_spec.rb
38
+ - spec/plugins/automaton-plugin2/auto/plugin2/task.rb
39
+ - spec/plugins/automaton-plugin2/auto/plugin2/task2.rb
40
+ - spec/plugins/automaton-plugin2/lib/plugin2.rb
41
+ - spec/plugins/user-automaton-plugin-0.0.0/auto/plugin/task.rb
42
+ - spec/plugins/user-automaton-plugin-0.0.0/lib/plugin.rb
43
+ - spec/spec.opts
44
+ - spec/spec_helper.rb
45
+ has_rdoc: true
46
+ homepage: http://github.com/winton/automaton
47
+ licenses: []
48
+
49
+ post_install_message:
50
+ rdoc_options: []
51
+
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: "0"
59
+ version:
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: "0"
65
+ version:
66
+ requirements: []
67
+
68
+ rubyforge_project:
69
+ rubygems_version: 1.3.5
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: Automate everything!
73
+ test_files: []
74
+