rutty 2.1.1 → 2.1.2
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.
- data/README.md +62 -7
- data/VERSION +1 -1
- data/lib/rutty.rb +31 -0
- data/lib/rutty/actions.rb +36 -0
- data/lib/rutty/config.rb +53 -1
- data/lib/rutty/consts.rb +10 -0
- data/lib/rutty/errors.rb +10 -0
- data/lib/rutty/helpers.rb +16 -1
- data/lib/rutty/node.rb +32 -2
- data/lib/rutty/nodes.rb +27 -0
- data/lib/rutty/version.rb +8 -1
- data/rutty.gemspec +1 -1
- metadata +3 -3
data/README.md
CHANGED
@@ -1,23 +1,79 @@
|
|
1
1
|
RuTTY
|
2
2
|
=====
|
3
3
|
|
4
|
-
RuTTY is a DSH implementation in Ruby.
|
4
|
+
RuTTY is a DSH implementation in Ruby. You can use it to execute shell commands on multiple remote
|
5
|
+
servers simultaneously using a tagging system to target just the servers you want.
|
6
|
+
|
7
|
+
Also supports SCP uploads to multiple remote servers using the same tagging system.
|
5
8
|
|
6
9
|
Requirements
|
7
10
|
------------
|
8
11
|
|
9
12
|
* Ruby >= 1.8.7 (Not tested on 1.9.x)
|
10
13
|
* Rubygems >= 1.3.7
|
14
|
+
|
15
|
+
###Development Requirements###
|
16
|
+
|
11
17
|
* Bundler >= 1.0.0
|
12
18
|
|
13
19
|
Installation
|
14
20
|
------------
|
15
21
|
|
16
|
-
$ sudo gem install
|
17
|
-
$
|
18
|
-
$
|
19
|
-
|
20
|
-
|
22
|
+
$ sudo gem install rutty
|
23
|
+
$ rutty init
|
24
|
+
$ rutty help
|
25
|
+
|
26
|
+
Usage
|
27
|
+
-----
|
28
|
+
|
29
|
+
###Init###
|
30
|
+
|
31
|
+
You must first initialize the RuTTY configuration and data directory with the `rutty init` command. This
|
32
|
+
command takes an optional argument to specify the directory to install into. If omitted, it will install
|
33
|
+
into `~/.rutty/`. Note that if you install into a directory other than the default, you will have to supply
|
34
|
+
the config to all the other commands with the `-c` option.
|
35
|
+
|
36
|
+
$ rutty init
|
37
|
+
create /Users/jlindsey/.rutty
|
38
|
+
create /Users/jlindsey/.rutty/defaults.yaml
|
39
|
+
create /Users/jlindsey/.rutty/nodes.yaml
|
40
|
+
|
41
|
+
|
42
|
+
###Adding Nodes###
|
43
|
+
|
44
|
+
After initialization, you must add nodes to the RuTTY config. This is done with the `rutty add_node` command.
|
45
|
+
Invoking `rutty help add_node` will give you a list of all the options to pass into it. Any options you don't pass
|
46
|
+
will be filled in from the defaults at `$RUTTY_HOME/defaults.yaml`.
|
47
|
+
|
48
|
+
$ rutty add_node example.com -u root -k /Users/jlindsey/.ssh/id_rsa --tags example,test
|
49
|
+
|
50
|
+
The above will add a node to the RuTTY config that looks like this (in YAML):
|
51
|
+
|
52
|
+
---
|
53
|
+
host: example.com
|
54
|
+
user: root
|
55
|
+
keypath: /Users/jlindsey/.ssh/id_rsa
|
56
|
+
tags:
|
57
|
+
- example
|
58
|
+
- test
|
59
|
+
port: 22
|
60
|
+
|
61
|
+
Note that the `port: 22` line was filled in from the defaults because it was not specified.
|
62
|
+
|
63
|
+
###Running Commands###
|
64
|
+
|
65
|
+
Now that we have a node, we can run commands on it. The default RuTTY command is the `dsh` action, so it
|
66
|
+
can be omitted. That is to say, the following two commands are identical:
|
67
|
+
|
68
|
+
$ rutty dsh -a uptime
|
69
|
+
$ rutty -a uptime
|
70
|
+
|
71
|
+
The `dsh` action can accept either a list of tags passed via `--tags` or the `-a` flag, which will run the command
|
72
|
+
on all defined nodes regardless of tags.
|
73
|
+
|
74
|
+
Note that any command that has any whitespace in it must be enclosed in quotes.
|
75
|
+
|
76
|
+
$ rutty -a "free -m"
|
21
77
|
|
22
78
|
TODO
|
23
79
|
----
|
@@ -28,7 +84,6 @@ TODO
|
|
28
84
|
* Implement delete_node command
|
29
85
|
* Make better printouts
|
30
86
|
* Documentation
|
31
|
-
* Tests
|
32
87
|
|
33
88
|
Copyright
|
34
89
|
---------
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.1.
|
1
|
+
2.1.2
|
data/lib/rutty.rb
CHANGED
@@ -7,7 +7,19 @@ require 'rutty/helpers'
|
|
7
7
|
require 'rutty/node'
|
8
8
|
require 'rutty/nodes'
|
9
9
|
|
10
|
+
##
|
11
|
+
# The RuTTY top-level module. Everything in the RuTTY gem is contained in this module.
|
12
|
+
#
|
13
|
+
# @author Josh Lindsey
|
14
|
+
# @since 2.0.0
|
10
15
|
module Rutty
|
16
|
+
|
17
|
+
##
|
18
|
+
# The Rutty::Runner class includes mixins from the other modules. All end-user interaction
|
19
|
+
# should be done through this class.
|
20
|
+
#
|
21
|
+
# @author Josh Lindsey
|
22
|
+
# @since 2.0.0
|
11
23
|
class Runner
|
12
24
|
attr_writer :config_dir
|
13
25
|
|
@@ -15,18 +27,37 @@ module Rutty
|
|
15
27
|
include Rutty::Helpers
|
16
28
|
include Rutty::Actions
|
17
29
|
|
30
|
+
##
|
31
|
+
# Initialize a new {Rutty::Runner} instance
|
32
|
+
#
|
33
|
+
# @param config_dir [String] Optional parameter specifying the directory RuTTY has been init'd into
|
18
34
|
def initialize config_dir = nil
|
19
35
|
self.config_dir = config_dir
|
20
36
|
end
|
21
37
|
|
38
|
+
##
|
39
|
+
# Lazy-load the {Rutty::Config} object for this instance, based on the config_dir param
|
40
|
+
# passed to {#initialize}.
|
41
|
+
#
|
42
|
+
# @return [Rutty::Config]
|
22
43
|
def config
|
23
44
|
@config ||= Rutty::Config.load_config self.config_dir
|
24
45
|
end
|
25
46
|
|
47
|
+
##
|
48
|
+
# Lazy-load the {Rutty::Nodes} object containing the user-defined nodes' connection info.
|
49
|
+
# Loads from the config_dir param passed to {#initialize}
|
50
|
+
#
|
51
|
+
# @return [Rutty::Nodes]
|
26
52
|
def nodes
|
27
53
|
@nodes ||= Rutty::Nodes.load_config self.config_dir
|
28
54
|
end
|
29
55
|
|
56
|
+
##
|
57
|
+
# If @config_dir is nil, returns {Rutty::Consts::CONF_DIR}. Otherwise return @config_dir.
|
58
|
+
#
|
59
|
+
# @see Rutty::Consts::CONF_DIR
|
60
|
+
# @return [String] The user-specified config directory, falling back to the default on nil
|
30
61
|
def config_dir
|
31
62
|
(@config_dir.nil? && Rutty::Consts::CONF_DIR) || @config_dir
|
32
63
|
end
|
data/lib/rutty/actions.rb
CHANGED
@@ -1,7 +1,20 @@
|
|
1
1
|
require 'rutty/consts'
|
2
2
|
|
3
3
|
module Rutty
|
4
|
+
|
5
|
+
##
|
6
|
+
# The primary mixin module containing the code executed by the rutty bin's actions.
|
7
|
+
#
|
8
|
+
# @author Josh Lindsey
|
9
|
+
# @since 2.0.0
|
4
10
|
module Actions
|
11
|
+
##
|
12
|
+
# Initialize the Rutty config file structure in the specified directory, or
|
13
|
+
# report that the files already exist there.
|
14
|
+
#
|
15
|
+
# @see Rutty::Runner#config_dir
|
16
|
+
# @param [String] dir The directory to install into. {Rutty::Runner#config_dir} ensures
|
17
|
+
# that this falls back to {Rutty::Consts::CONF_DIR} if not passed in by the user.
|
5
18
|
def init dir
|
6
19
|
general_file = File.join(dir, Rutty::Consts::GENERAL_CONF_FILE)
|
7
20
|
nodes_file = File.join(dir, Rutty::Consts::NODES_CONF_FILE)
|
@@ -40,6 +53,12 @@ module Rutty
|
|
40
53
|
end
|
41
54
|
end
|
42
55
|
|
56
|
+
##
|
57
|
+
# Add a new user-defined node to the datastore file.
|
58
|
+
#
|
59
|
+
# @see http://visionmedia.github.com/commander/
|
60
|
+
# @param [Array] args ARGV passed by the bin
|
61
|
+
# @param [Object] options The parsed options object as passed by the bin
|
43
62
|
def add_node args, options
|
44
63
|
raise Rutty::BadUsage.new "Must supply a hostname or IP address.
|
45
64
|
See `rutty help add_node' for usage" if args.empty?
|
@@ -54,12 +73,23 @@ module Rutty
|
|
54
73
|
self.nodes.write_config self.config_dir
|
55
74
|
end
|
56
75
|
|
76
|
+
##
|
77
|
+
# List all the user-defined nodes currently stored in the datastore file.
|
78
|
+
#
|
79
|
+
# @see (see #add_node)
|
80
|
+
# @param (see #add_node)
|
57
81
|
def list_nodes args, options
|
58
82
|
require 'pp'
|
59
83
|
|
60
84
|
pp self.nodes.filter(options)
|
61
85
|
end
|
62
86
|
|
87
|
+
##
|
88
|
+
# Cycle through all the user-defined nodes, filtered by the options, connect to them
|
89
|
+
# and run the specified command on them.
|
90
|
+
#
|
91
|
+
# @see (see #add_node)
|
92
|
+
# @param (see #add_node)
|
63
93
|
def dsh args, options
|
64
94
|
# TODO: Clean this up, it's pretty hard to read and follow
|
65
95
|
|
@@ -138,6 +168,12 @@ module Rutty
|
|
138
168
|
pp @returns
|
139
169
|
end
|
140
170
|
|
171
|
+
##
|
172
|
+
# Cycle through all the user-defined nodes, filtered by the options, connect to them
|
173
|
+
# and upload the specified file(s).
|
174
|
+
#
|
175
|
+
# @see (see #add_node)
|
176
|
+
# @param (see #add_node)
|
141
177
|
def scp args, options
|
142
178
|
check_installed!
|
143
179
|
raise Rutty::BadUsage.new "Must supply a local path and a remote path" unless args.length == 2
|
data/lib/rutty/config.rb
CHANGED
@@ -1,7 +1,29 @@
|
|
1
|
-
# http://mjijackson.com/2010/02/flexible-ruby-config-objects
|
2
1
|
module Rutty
|
2
|
+
|
3
|
+
##
|
4
|
+
# Flexible config class able to use both hash accessors and object accessors. Nested
|
5
|
+
# attributes are also instances of this class, allowing for object (dot) style accessor
|
6
|
+
# chaining.
|
7
|
+
#
|
8
|
+
# @see http://mjijackson.com/2010/02/flexible-ruby-config-objects
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# config = Config.new :foo => "bar", :test => "baz", :widget => { :another => "string" }
|
12
|
+
#
|
13
|
+
# config.foo # => "bar"
|
14
|
+
# config.widget.another # => "string"
|
15
|
+
#
|
16
|
+
# @author Michael Jackson
|
17
|
+
# @author Josh Lindsey
|
18
|
+
# @since 2.0.0
|
3
19
|
class Config
|
4
20
|
class << self
|
21
|
+
##
|
22
|
+
# Loads the default config data from the yaml file in the specified config dir.
|
23
|
+
#
|
24
|
+
# @see Rutty::Consts::GENERAL_CONF_FILE
|
25
|
+
# @param [String] dir The directory to look in for the file specified by {Rutty::Consts::GENERAL_CONF_FILE}
|
26
|
+
# @return [Rutty::Config] The populated {Config} instance
|
5
27
|
def load_config dir
|
6
28
|
require 'yaml'
|
7
29
|
|
@@ -10,21 +32,41 @@ module Rutty
|
|
10
32
|
end
|
11
33
|
end
|
12
34
|
|
35
|
+
##
|
36
|
+
# Returns a new {Config} populated with the specified data hash.
|
37
|
+
#
|
38
|
+
# @see #update!
|
39
|
+
# @param (see #update!)
|
13
40
|
def initialize(data={})
|
14
41
|
@data = {}
|
15
42
|
update!(data)
|
16
43
|
end
|
17
44
|
|
45
|
+
##
|
46
|
+
# Updates this instance's @data attribute with the specified data hash.
|
47
|
+
#
|
48
|
+
# @param [Hash] data Data hash to iterate over
|
49
|
+
# @see #[]=
|
18
50
|
def update!(data)
|
19
51
|
data.each do |key, value|
|
20
52
|
self[key] = value
|
21
53
|
end
|
22
54
|
end
|
23
55
|
|
56
|
+
##
|
57
|
+
# Retrieve the specified key via Hash accessor syntax.
|
58
|
+
#
|
59
|
+
# @param [Symbol, String] key The key to lookup
|
60
|
+
# @return [Object] The object corresponding to the key
|
24
61
|
def [](key)
|
25
62
|
@data[key.to_sym]
|
26
63
|
end
|
27
64
|
|
65
|
+
##
|
66
|
+
# Set the specified key as the specified value via Hash accessor syntax.
|
67
|
+
#
|
68
|
+
# @param [Symbol, String] key The key to set
|
69
|
+
# @param [Object] value The value to set into the key
|
28
70
|
def []=(key, value)
|
29
71
|
if value.class == Hash
|
30
72
|
@data[key.to_sym] = Config.new(value)
|
@@ -33,10 +75,20 @@ module Rutty
|
|
33
75
|
end
|
34
76
|
end
|
35
77
|
|
78
|
+
##
|
79
|
+
# Simply returns this instance's @data attribute, which is internally stored as a hash.
|
80
|
+
#
|
81
|
+
# @return [Hash] The @data attribute
|
36
82
|
def to_hash
|
37
83
|
@data
|
38
84
|
end
|
39
85
|
|
86
|
+
##
|
87
|
+
# Allows for object accessor (dot) syntax to access the stored data.
|
88
|
+
# If the missing method ends with an equals, calls {#[]=}, otherwise calls {#[]}
|
89
|
+
#
|
90
|
+
# @param [Symbol] sym The method symbol
|
91
|
+
# @param [*Array] args The splatted array of method arguments
|
40
92
|
def method_missing(sym, *args)
|
41
93
|
if sym.to_s =~ /(.+)=$/
|
42
94
|
self[$1] = args.first
|
data/lib/rutty/consts.rb
CHANGED
@@ -1,10 +1,20 @@
|
|
1
1
|
module Rutty
|
2
|
+
##
|
3
|
+
# Simple container module for constants.
|
4
|
+
#
|
5
|
+
# @author Josh Lindsey
|
6
|
+
# @since 2.0.0
|
2
7
|
module Consts
|
8
|
+
## Name of the general (defaults) config file
|
3
9
|
GENERAL_CONF_FILE = 'defaults.yaml'
|
10
|
+
## Name of the datastore file for user-defined nodes
|
4
11
|
NODES_CONF_FILE = 'nodes.yaml'
|
5
12
|
|
13
|
+
## Default configuaration storage directory
|
6
14
|
CONF_DIR = File.join(ENV['HOME'], '.rutty')
|
15
|
+
## Default general (defaults) config file location
|
7
16
|
GENERAL_CONF = File.join(CONF_DIR, GENERAL_CONF_FILE)
|
17
|
+
## Default nodes datastore file location
|
8
18
|
NODES_CONF = File.join(CONF_DIR, NODES_CONF_FILE)
|
9
19
|
end
|
10
20
|
end
|
data/lib/rutty/errors.rb
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
module Rutty
|
2
|
+
##
|
3
|
+
# Raised by {Rutty::Helpers#check_installed!} if the check fails.
|
4
|
+
#
|
5
|
+
# @author Josh Lindsey
|
6
|
+
# @since 2.0.0
|
2
7
|
class NotInstalledError < StandardError; end
|
3
8
|
|
9
|
+
##
|
10
|
+
# Raised by various {Rutty::Actions} methods on invalid options, etc.
|
11
|
+
#
|
12
|
+
# @author Josh Lindsey
|
13
|
+
# @since 2.0.0
|
4
14
|
class BadUsage < StandardError; end
|
5
15
|
end
|
data/lib/rutty/helpers.rb
CHANGED
@@ -1,9 +1,19 @@
|
|
1
1
|
require 'rutty/errors'
|
2
|
-
require 'rutty/consts'
|
3
2
|
require 'rutty/version'
|
4
3
|
|
5
4
|
module Rutty
|
5
|
+
|
6
|
+
##
|
7
|
+
# Simple mixin module for miscellaneous methods that don't fit in elsewhere.
|
8
|
+
#
|
9
|
+
# @author Josh Lindsey
|
10
|
+
# @since 2.0.0
|
6
11
|
module Helpers
|
12
|
+
##
|
13
|
+
# Check to ensure the config dir exists. Method expects this module to be included in a
|
14
|
+
# class or module where self.config_dir is meaningful, such as {Rutty::Runner}.
|
15
|
+
#
|
16
|
+
# @raise [Rutty::NotInstalledError] If file cannot be found
|
7
17
|
def check_installed!
|
8
18
|
unless File.exists? self.config_dir
|
9
19
|
raise Rutty::NotInstalledError.new %Q(Can't find conf directory at #{self.config_dir}.
|
@@ -11,6 +21,11 @@ module Rutty
|
|
11
21
|
end
|
12
22
|
end
|
13
23
|
|
24
|
+
##
|
25
|
+
# Returns the version string contained in {Rutty::Version::STRING}. Used by the rutty bin.
|
26
|
+
#
|
27
|
+
# @see (see Rutty::Version)
|
28
|
+
# @return [String] The version string
|
14
29
|
def self.get_version
|
15
30
|
Rutty::Version::STRING
|
16
31
|
end
|
data/lib/rutty/node.rb
CHANGED
@@ -1,21 +1,51 @@
|
|
1
1
|
require 'rutty/config'
|
2
|
-
require 'rutty/consts'
|
3
2
|
|
4
3
|
module Rutty
|
5
|
-
|
4
|
+
|
5
|
+
##
|
6
|
+
# A wrapper class representing an individual node. Normally contained by {Rutty::Nodes}.
|
7
|
+
#
|
8
|
+
# @see Rutty::Config
|
9
|
+
# @author Josh Lindsey
|
10
|
+
# @since 2.0.0
|
11
|
+
class Node < Config
|
12
|
+
##
|
13
|
+
# Initialize a new {Rutty::Node} instance by merging the user-provided data with
|
14
|
+
# the configured defaults.
|
15
|
+
#
|
16
|
+
# @see Rutty::Config#initialize
|
17
|
+
# @param [Hash] data The data provided by the user
|
18
|
+
# @param [Hash] defaults The defaults data provided by the {Rutty::Config} class
|
6
19
|
def initialize data, defaults = {}
|
7
20
|
merged_data = defaults.merge data
|
8
21
|
super merged_data
|
9
22
|
end
|
10
23
|
|
24
|
+
##
|
25
|
+
# Whether this object's tags array includes the specified tag.
|
26
|
+
#
|
27
|
+
# @param [String] tag The tag string to check for
|
11
28
|
def has_tag? tag
|
12
29
|
self.tags.include? tag
|
13
30
|
end
|
14
31
|
|
32
|
+
##
|
33
|
+
# Relation of this {Rutty::Node} to another {Rutty::Node}. Used for sorting.
|
34
|
+
# Compares the host property of the nodes, as it's the only property guaranteed to be
|
35
|
+
# set and unique.
|
36
|
+
#
|
37
|
+
# @see http://ruby-doc.org/core/classes/String.html#M000763
|
38
|
+
# @param [Rutty::Node] other The other {Rutty::Node} to compare to
|
39
|
+
# @return [Integer] Relation of self to other: -1 for less-than, 0 for equal-to, 1 for greater-than
|
15
40
|
def <=> other
|
16
41
|
self.host <=> other.host
|
17
42
|
end
|
18
43
|
|
44
|
+
##
|
45
|
+
# Checks for object eqality. Checks each property of this {Node} against the other.
|
46
|
+
#
|
47
|
+
# @param (see Rutty::Node#<=>)
|
48
|
+
# @return [Boolean]
|
19
49
|
def == other
|
20
50
|
self.host == other.host and
|
21
51
|
self.port == other.port and
|
data/lib/rutty/nodes.rb
CHANGED
@@ -2,14 +2,36 @@ require 'rutty/node'
|
|
2
2
|
require 'rutty/consts'
|
3
3
|
|
4
4
|
module Rutty
|
5
|
+
|
6
|
+
##
|
7
|
+
# Simple container class for {Rutty::Node} instances. Contains methods to load node data from file,
|
8
|
+
# write data back to the file, and filter nodes based on user-supplied criteria.
|
9
|
+
#
|
10
|
+
# @author Josh Lindsey
|
11
|
+
# @since 2.1.0
|
5
12
|
class Nodes < Array
|
6
13
|
class << self
|
14
|
+
##
|
15
|
+
# Loads the users's node data from the yaml file contained in the specified dir.
|
16
|
+
#
|
17
|
+
# @param [String] dir The directory to look in for the filename specified by {Rutty::Consts::NODES_CONF_FILE}
|
18
|
+
# @return [Rutty::Nodes] The filled instance of {Rutty::Node} objects
|
19
|
+
# @see Rutty::Consts::NODES_CONF_FILE
|
7
20
|
def load_config dir
|
8
21
|
require 'yaml'
|
9
22
|
Rutty::Nodes.new YAML.load(File.open(File.join(dir, Rutty::Consts::NODES_CONF_FILE)).read)
|
10
23
|
end
|
11
24
|
end
|
12
25
|
|
26
|
+
##
|
27
|
+
# Filters out the {Rutty::Node} objects contained in this instance based on user-defined criteria.
|
28
|
+
#
|
29
|
+
# @param [Hash, #[]] opts The filter criteria
|
30
|
+
# @option opts [String] :keypath (nil) The path to the private key
|
31
|
+
# @option opts [String] :user (nil) The user to login as
|
32
|
+
# @option opts [Integer] :port (nil) The port to connect to
|
33
|
+
# @option opts [Array<String>] :tags (nil) The tags to filter by
|
34
|
+
# @return [Array] An Array containing the {Rutty::Node} objects after filtering
|
13
35
|
def filter opts = {}
|
14
36
|
return self if opts[:all]
|
15
37
|
|
@@ -23,6 +45,11 @@ module Rutty
|
|
23
45
|
ary
|
24
46
|
end
|
25
47
|
|
48
|
+
##
|
49
|
+
# Writes the updated nodes config back into the nodes.yaml file in the specified dir.
|
50
|
+
#
|
51
|
+
# @param (see Rutty::Nodes.load_config)
|
52
|
+
# @see (see Rutty::Nodes.load_config)
|
26
53
|
def write_config dir
|
27
54
|
File.open(File.join(dir, Rutty::Consts::NODES_CONF_FILE), 'w') do |f|
|
28
55
|
YAML.dump(self, f)
|
data/lib/rutty/version.rb
CHANGED
@@ -1,8 +1,15 @@
|
|
1
1
|
module Rutty
|
2
|
+
|
3
|
+
##
|
4
|
+
# The current version of the gem, expressed in Ruby code so it can
|
5
|
+
# be accessed programmatically.
|
6
|
+
#
|
7
|
+
# @author Josh Lindsey
|
8
|
+
# @see http://semver.org
|
2
9
|
module Version
|
3
10
|
MAJOR = 2
|
4
11
|
MINOR = 1
|
5
|
-
PATCH =
|
12
|
+
PATCH = 2
|
6
13
|
BUILD = nil
|
7
14
|
|
8
15
|
STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join('.')
|
data/rutty.gemspec
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rutty
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 2
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 2.1.
|
9
|
+
- 2
|
10
|
+
version: 2.1.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Josh Lindsey
|