chaindrive 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.
- data/.gitignore +21 -0
- data/.ruby-version +1 -0
- data/.travis.yml +12 -0
- data/Gemfile +6 -0
- data/Guardfile +25 -0
- data/LICENSE.txt +22 -0
- data/README.md +28 -0
- data/Rakefile +1 -0
- data/chaindrive.gemspec +32 -0
- data/etc/Gearfile +4 -0
- data/etc/rbenv.gearspec +13 -0
- data/lib/chaindrive.rb +76 -0
- data/lib/chaindrive/command.rb +43 -0
- data/lib/chaindrive/command/config.rb +38 -0
- data/lib/chaindrive/command/install.rb +16 -0
- data/lib/chaindrive/command/upgrade.rb +14 -0
- data/lib/chaindrive/config.rb +28 -0
- data/lib/chaindrive/environment.rb +19 -0
- data/lib/chaindrive/gear.rb +28 -0
- data/lib/chaindrive/gear/provisioner.rb +10 -0
- data/lib/chaindrive/gear/specification.rb +18 -0
- data/lib/chaindrive/gearbox.rb +26 -0
- data/lib/chaindrive/gearbox/isolation.rb +10 -0
- data/lib/chaindrive/gearbox/specification.rb +11 -0
- data/lib/chaindrive/index.rb +39 -0
- data/lib/chaindrive/templates/Gearfile +4 -0
- data/lib/chaindrive/user.rb +14 -0
- data/lib/chaindrive/version.rb +4 -0
- data/lib/hashie/blash.rb +230 -0
- data/script/bootstrap +2 -0
- data/spec/chaindrive/user_spec.rb +13 -0
- metadata +246 -0
data/.gitignore
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.9.3
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
guard :minitest do
|
4
|
+
# with Minitest::Unit
|
5
|
+
watch(%r{^test/(.*)\/?test_(.*)\.rb})
|
6
|
+
watch(%r{^lib/(.*/)?([^/]+)\.rb}) { |m| "test/#{m[1]}test_#{m[2]}.rb" }
|
7
|
+
watch(%r{^test/test_helper\.rb}) { 'test' }
|
8
|
+
|
9
|
+
# with Minitest::Spec
|
10
|
+
watch(%r{^spec/(.*)_spec\.rb})
|
11
|
+
watch(%r{^lib/(.+)\.rb}) { |m| "spec/#{m[1]}_spec.rb" }
|
12
|
+
watch(%r{^spec/spec_helper\.rb}) { 'spec' }
|
13
|
+
end
|
14
|
+
|
15
|
+
guard :minitest do
|
16
|
+
# with Minitest::Unit
|
17
|
+
watch(%r{^test/(.*)\/?test_(.*)\.rb})
|
18
|
+
watch(%r{^lib/(.*/)?([^/]+)\.rb}) { |m| "test/#{m[1]}test_#{m[2]}.rb" }
|
19
|
+
watch(%r{^test/test_helper\.rb}) { 'test' }
|
20
|
+
|
21
|
+
# with Minitest::Spec
|
22
|
+
watch(%r{^spec/(.*)_spec\.rb})
|
23
|
+
watch(%r{^lib/(.+)\.rb}) { |m| "spec/#{m[1]}_spec.rb" }
|
24
|
+
watch(%r{^spec/spec_helper\.rb}) { 'spec' }
|
25
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 John Bellone
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# Chaindrive [](http://travis-ci.org/chaindrive/chaindrive)
|
2
|
+
===================================
|
3
|
+
|
4
|
+
## Installation
|
5
|
+
|
6
|
+
Add this line to your application's Gemfile:
|
7
|
+
|
8
|
+
gem 'chaindrive'
|
9
|
+
|
10
|
+
And then execute:
|
11
|
+
|
12
|
+
$ bundle
|
13
|
+
|
14
|
+
Or install it yourself as:
|
15
|
+
|
16
|
+
$ gem install chaindrive
|
17
|
+
|
18
|
+
## Usage
|
19
|
+
|
20
|
+
$ chaindrive help
|
21
|
+
|
22
|
+
## Contributing
|
23
|
+
|
24
|
+
1. Fork it
|
25
|
+
y2. Create your feature branch (`git checkout -b my-new-feature`)
|
26
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
27
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
28
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/chaindrive.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'chaindrive/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "chaindrive"
|
8
|
+
spec.version = Chaindrive::VERSION
|
9
|
+
spec.authors = ["John Bellone"]
|
10
|
+
spec.email = ["john.bellone.jr@gmail.com"]
|
11
|
+
spec.description = %q{A tool to describe complex software systems.}
|
12
|
+
spec.summary = IO.read(File.join(File.dirname(__FILE__), 'README.md'))
|
13
|
+
spec.homepage = "http://chaindrive.io"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency 'thor', '~> 0.18'
|
22
|
+
spec.add_dependency 'multi_json', '~> 1.0'
|
23
|
+
spec.add_dependency 'hashie', '~> 2.0'
|
24
|
+
spec.add_dependency 'colorize', '~> 0.6'
|
25
|
+
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
27
|
+
spec.add_development_dependency "rake"
|
28
|
+
spec.add_development_dependency 'pry'
|
29
|
+
spec.add_development_dependency 'pry-debugger'
|
30
|
+
spec.add_development_dependency 'pry-stack_explorer'
|
31
|
+
spec.add_development_dependency 'guard-minitest'
|
32
|
+
end
|
data/etc/Gearfile
ADDED
data/etc/rbenv.gearspec
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
Chaindrive::Gear.define :rbenv do |gear|
|
3
|
+
gear.name = 'rbenv'
|
4
|
+
gear.version = '0.1.0'
|
5
|
+
gear.description = 'Setup the Ruby environment'
|
6
|
+
gear.long_description = 'Setup the Ruby environment'
|
7
|
+
gear.homepage = 'https://github.com/chaindrive/gear-rbenv'
|
8
|
+
gear.maintainer = {
|
9
|
+
name: 'John Bellone',
|
10
|
+
email: 'john.bellone.jr@gmail.com',
|
11
|
+
github: 'johnbellone'
|
12
|
+
}
|
13
|
+
end
|
data/lib/chaindrive.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'thor'
|
3
|
+
require 'hashie'
|
4
|
+
require 'hashie/blash'
|
5
|
+
require 'multi_json'
|
6
|
+
require 'logger'
|
7
|
+
require 'fileutils'
|
8
|
+
|
9
|
+
require 'chaindrive/version'
|
10
|
+
require 'chaindrive/config'
|
11
|
+
require 'chaindrive/environment'
|
12
|
+
require 'chaindrive/command'
|
13
|
+
require 'chaindrive/gear'
|
14
|
+
require 'chaindrive/gearbox'
|
15
|
+
require 'chaindrive/user'
|
16
|
+
|
17
|
+
# @abstract
|
18
|
+
module Chaindrive
|
19
|
+
class << self
|
20
|
+
|
21
|
+
def chaindrive_path
|
22
|
+
File.join(Dir.home, '.chaindrive')
|
23
|
+
end
|
24
|
+
|
25
|
+
def user_config
|
26
|
+
File.join(chaindrive_path, 'config.json')
|
27
|
+
end
|
28
|
+
|
29
|
+
def cache
|
30
|
+
File.join(user_path, 'cache')
|
31
|
+
end
|
32
|
+
|
33
|
+
def root
|
34
|
+
Dir.pwd
|
35
|
+
end
|
36
|
+
|
37
|
+
def root_config
|
38
|
+
File.join(root, '.chaindrive/config.json')
|
39
|
+
end
|
40
|
+
|
41
|
+
def logger
|
42
|
+
$stdout.sync = true
|
43
|
+
@logger ||= Logger.new($stdout).tap do |logger|
|
44
|
+
logger.level = Logger::INFO
|
45
|
+
logger.formatter = proc do |severity, datetime, progname, msg|
|
46
|
+
case severity
|
47
|
+
when Logger::ERROR
|
48
|
+
return msg.colorize(:magenta)
|
49
|
+
when Logger::FATAL
|
50
|
+
return msg.colorize(:red)
|
51
|
+
when Logger::WARN
|
52
|
+
return msg.colorize(:yellow)
|
53
|
+
when Logger::INFO
|
54
|
+
return msg.colorize(:white)
|
55
|
+
end
|
56
|
+
|
57
|
+
msg
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Read and evaluate a file from disk to configure.
|
63
|
+
# @param [String] path on disk where file is located
|
64
|
+
def load(filename = nil)
|
65
|
+
filename ||= File.join(Chaindrive.path, 'Gearfile')
|
66
|
+
raise IOError, "'Gearfile' does not exist!" unless File.exists?(filename)
|
67
|
+
begin
|
68
|
+
Kernel.load(filename)
|
69
|
+
rescue LoadError => e
|
70
|
+
logger.error "Failed loading '#{filename}': #{e.message}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'chaindrive/command/config'
|
3
|
+
require 'chaindrive/command/install'
|
4
|
+
require 'chaindrive/command/upgrade'
|
5
|
+
|
6
|
+
module Chaindrive
|
7
|
+
module Command
|
8
|
+
|
9
|
+
# Entry point for the command-line interface of the application.
|
10
|
+
class CLI < Thor
|
11
|
+
option :debug, type: :boolean, desc: 'Debug mode'
|
12
|
+
option :config, type: :string, desc: 'Configuration file'
|
13
|
+
option :verbose, type: :boolean, desc: 'Verbosity'
|
14
|
+
|
15
|
+
desc 'init', 'Generates a Gearfile into the working directory.'
|
16
|
+
def init
|
17
|
+
if File.exists?('Gearfile')
|
18
|
+
Chaindrive.logger.error "Gearfile already exists at '#{Dir.pwd}'"
|
19
|
+
exit 1
|
20
|
+
end
|
21
|
+
|
22
|
+
Chaindrive.logger.info "Writing Gearfile to '#{Dir.pwd}'"
|
23
|
+
FileUtils.cp(File.expand_path('templates/Gearfile', __FILE__), 'Gearfile')
|
24
|
+
end
|
25
|
+
|
26
|
+
desc 'env', 'Prints run-time environment variables.'
|
27
|
+
def env
|
28
|
+
environment = Environment.new(opts)
|
29
|
+
puts environment.inspect
|
30
|
+
end
|
31
|
+
|
32
|
+
desc "config", "View and modify configuration for application"
|
33
|
+
subcommand 'config', Config
|
34
|
+
|
35
|
+
desc 'install', 'Install gear components'
|
36
|
+
subcommand 'install', Install
|
37
|
+
|
38
|
+
desc 'upgrade', 'Upgrade gear components'
|
39
|
+
subcommand 'upgrade', Upgrade
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module Chaindrive
|
3
|
+
module Command
|
4
|
+
|
5
|
+
# Public - Manages the application configuration and runtime options.
|
6
|
+
class Config < Thor
|
7
|
+
namespace :config
|
8
|
+
|
9
|
+
method_option :global, type: :boolean, default: false
|
10
|
+
method_option :system, type: :boolean, default: false
|
11
|
+
method_option :local, type: :boolean, default: true
|
12
|
+
method_option :file, type: :string, default: false
|
13
|
+
method_option :unset, type: :boolean, default: false
|
14
|
+
desc 'set [-c] [NAME] [VALUE]', 'Set the configuration for the application'
|
15
|
+
def set(name, value)
|
16
|
+
env = Chaindrive::Environment.new(options)
|
17
|
+
if Chaindrive::Config.method_defined?(name.to_sym)
|
18
|
+
env.config[name.to_sym] = value
|
19
|
+
env.config.save!
|
20
|
+
else
|
21
|
+
Chaindrive.logger.warn "Configuration can not set '#{name}' property."
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
desc 'get [NAME]', 'Get the configuration for the application'
|
26
|
+
def get(name)
|
27
|
+
env = Chaindrive::Environment.new(options)
|
28
|
+
if Chaindrive::Config.method_defined?(name.to_sym)
|
29
|
+
puts env.config[name.to_sym] if env.config.send(name.to_sym)
|
30
|
+
else
|
31
|
+
Chaindrive.logger.warn "Configuration does not contain '#{name}' property."
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module Chaindrive
|
3
|
+
|
4
|
+
# Define the basic settings for the Chaindrive runtime environment. These
|
5
|
+
# are directly loaded from on-disk JSON files.
|
6
|
+
class Config < Hashie::Dash
|
7
|
+
property :user, with: lambda { |h| User.new(h) }
|
8
|
+
|
9
|
+
# Construct a JSON configuration from disk.
|
10
|
+
# @param [String] filename Path to the configuration file.
|
11
|
+
def initialize(filename)
|
12
|
+
# Load up the disk configuration if it exists.
|
13
|
+
super MultiJson.load(IO.read(filename)) if File.exists?(filename)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Write the JSON configuration file to disk.
|
17
|
+
# @param [String] filename Path to save configuration file.
|
18
|
+
def save(filename)
|
19
|
+
# Create the configuration directory if it does not exist.
|
20
|
+
dp = File.expand_path(File.dirname(filename))
|
21
|
+
FileUtils.mkdir_p(dp) unless File.directory?(dp)
|
22
|
+
fail SystemCallError, "Failed saving '#{dp}'" unless File.directory?(dp)
|
23
|
+
|
24
|
+
IO.write(filename, MultiJson.dump(self, pretty: true))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module Chaindrive
|
3
|
+
|
4
|
+
# @abstract Define an object container which will house all of the
|
5
|
+
# information about a single kick of Chaindrive.
|
6
|
+
class Environment
|
7
|
+
attr_reader :config, :config_file
|
8
|
+
|
9
|
+
# Create a new run-time environment object to maintain application state.
|
10
|
+
# @param [Hash] opts run-time parameters to affect configuration
|
11
|
+
def initialize(opts = {})
|
12
|
+
@config_file = opts[:config] if File.exists?(opts[:config])
|
13
|
+
@config_file ||= Chaindrive.root_config if File.exists?(Chaindrive.root_config)
|
14
|
+
@config_file ||= Chaindrive.user_config
|
15
|
+
@config = Config.new(@config_file)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'chaindrive/gear/provisioner'
|
3
|
+
require 'chaindrive/gear/specification'
|
4
|
+
|
5
|
+
module Chaindrive
|
6
|
+
|
7
|
+
# @abstract
|
8
|
+
module Gear
|
9
|
+
class << self
|
10
|
+
attr_reader :specifications
|
11
|
+
|
12
|
+
# Produce a Gear Specification from a block and hash.
|
13
|
+
#
|
14
|
+
# @param [Hash] name
|
15
|
+
# @param [Block] &block
|
16
|
+
# @return [Specification]
|
17
|
+
def define(name = nil, &block)
|
18
|
+
hash = { name: name.to_s } if name
|
19
|
+
@@specifications ||= []
|
20
|
+
Hashie::Blash.new(hash).tap do |m|
|
21
|
+
yield m if block_given?
|
22
|
+
return Specification.new(m).tap { |s| @@specifications << s }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module Chaindrive
|
3
|
+
module Gear
|
4
|
+
|
5
|
+
# Define representation of a single piece of infrastructure.
|
6
|
+
class Specification < Hashie::Trash
|
7
|
+
property :name, required: true
|
8
|
+
property :version, required: true
|
9
|
+
property :description, required: true
|
10
|
+
property :license, required: true
|
11
|
+
property :maintainer, required: true, transform_with: lambda { |h| h.to_a }
|
12
|
+
property :long_description
|
13
|
+
property :homepage
|
14
|
+
property :provisioner, transform_with: lambda { |h| puts h.inspect }
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'chaindrive/gearbox/specification'
|
3
|
+
|
4
|
+
module Chaindrive
|
5
|
+
|
6
|
+
# @abstract The reproducible definition of a system.
|
7
|
+
module Gearbox
|
8
|
+
class << self
|
9
|
+
attr_reader :specifications
|
10
|
+
|
11
|
+
# Produce a Gearbox Specification from a block and hash.
|
12
|
+
#
|
13
|
+
# @param [String] role String to define the unique type.
|
14
|
+
# @return [Specification] Constructed configuration of Gearbox.
|
15
|
+
def define(role = nil, &block)
|
16
|
+
hash = { role: role.to_s } if role
|
17
|
+
@@specifications ||= []
|
18
|
+
Hashie::Blash.new(hash).tap do |m|
|
19
|
+
yield m if block_given?
|
20
|
+
return Specification.new(m).tap { |s| @@specifications << s }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module Chaindrive
|
3
|
+
class Index
|
4
|
+
attr_reader :sources, :gears, :groups
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@sources = []
|
8
|
+
@groups = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def source(source, opts = {})
|
12
|
+
source = 'http://chaindrive.io' if source == :chaindrive
|
13
|
+
if opts[:prepend]
|
14
|
+
@sources = [ source ] | @sources
|
15
|
+
else
|
16
|
+
@sources << source
|
17
|
+
end
|
18
|
+
|
19
|
+
yield if block_given?
|
20
|
+
source
|
21
|
+
end
|
22
|
+
|
23
|
+
def group(*args, &block)
|
24
|
+
@groups.concat args
|
25
|
+
yield
|
26
|
+
ensure
|
27
|
+
args.each { @groups.pop }
|
28
|
+
end
|
29
|
+
|
30
|
+
def gear(name, *args)
|
31
|
+
spec = { name: name.to_s }
|
32
|
+
end
|
33
|
+
|
34
|
+
def gearbox(name, *args, &block)
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module Chaindrive
|
3
|
+
|
4
|
+
# @abstract Define the structure which represents a User in the Chaindrive
|
5
|
+
# application environment.
|
6
|
+
class User < Hashie::Dash
|
7
|
+
property :name, required: true
|
8
|
+
property :github
|
9
|
+
property :email
|
10
|
+
property :twitter
|
11
|
+
property :homepage
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
data/lib/hashie/blash.rb
ADDED
@@ -0,0 +1,230 @@
|
|
1
|
+
require 'hashie/hash'
|
2
|
+
|
3
|
+
module Hashie
|
4
|
+
# Blash allows you to create Mash-like objects with a block syntax
|
5
|
+
# for creating nested hashes. This is useful for building deeply
|
6
|
+
# nested configuration hashes, similar in style to many dsl based
|
7
|
+
# configuration files.
|
8
|
+
#
|
9
|
+
# A Blash will look at the methods you pass it and perform operations
|
10
|
+
# based on the following rules:
|
11
|
+
#
|
12
|
+
# * No punctuation: Returns the value of the hash for that key, or nil if none exists.
|
13
|
+
# * With Block (<tt>{...}</tt>): Sets key to and yields a new blash
|
14
|
+
# * Assignment (<tt>=</tt>): Sets the attribute of the given method name.
|
15
|
+
# * Existence (<tt>?</tt>): Returns true or false depending on whether that key has been set.
|
16
|
+
#
|
17
|
+
# == Basic Example
|
18
|
+
#
|
19
|
+
# blash = Blash.new
|
20
|
+
# blash.name? # => false
|
21
|
+
# blash.name = "Bob"
|
22
|
+
# blash.name # => "Bob"
|
23
|
+
# blash.name? # => true
|
24
|
+
#
|
25
|
+
# == Hash Conversion Example
|
26
|
+
#
|
27
|
+
# hash = {:a => {:b => 23, :d => {:e => "abc"}}, :f => [{:g => 44, :h => 29}, 12]}
|
28
|
+
# blash = Blash.new(hash)
|
29
|
+
# blash.a.b # => 23
|
30
|
+
# blash.a.d.e # => "abc"
|
31
|
+
# blash.f.first.g # => 44
|
32
|
+
# blash.f.last # => 12
|
33
|
+
#
|
34
|
+
# == Block Example
|
35
|
+
#
|
36
|
+
# blash = Blash.new
|
37
|
+
# blash.author do |a|
|
38
|
+
# a.name = "Michael Bleigh"
|
39
|
+
# end
|
40
|
+
# blash.author # => <Blash name="Michael Bleigh">
|
41
|
+
# blash.author.name # => "Michael Bleigh"
|
42
|
+
#
|
43
|
+
class Blash < Hash
|
44
|
+
include Hashie::PrettyInspect
|
45
|
+
alias_method :to_s, :inspect
|
46
|
+
|
47
|
+
# If you pass in an existing hash, it will
|
48
|
+
# convert it to a Blash including recursively
|
49
|
+
# descending into arrays and hashes, converting
|
50
|
+
# them as well.
|
51
|
+
def initialize(source_hash = nil, default = nil, &blk)
|
52
|
+
deep_update(source_hash) if source_hash
|
53
|
+
default ? super(default) : super(&blk)
|
54
|
+
end
|
55
|
+
|
56
|
+
class << self; alias [] new; end
|
57
|
+
|
58
|
+
def id #:nodoc:
|
59
|
+
self["id"]
|
60
|
+
end
|
61
|
+
|
62
|
+
def type #:nodoc:
|
63
|
+
self["type"]
|
64
|
+
end
|
65
|
+
|
66
|
+
alias_method :regular_reader, :[]
|
67
|
+
alias_method :regular_writer, :[]=
|
68
|
+
|
69
|
+
# Retrieves an attribute set in the Blash. Will convert
|
70
|
+
# any key passed in to a string before retrieving.
|
71
|
+
def custom_reader(key)
|
72
|
+
value = regular_reader(convert_key(key))
|
73
|
+
yield value if block_given?
|
74
|
+
value
|
75
|
+
end
|
76
|
+
|
77
|
+
# Sets an attribute in the Blash. Key will be converted to
|
78
|
+
# a string before it is set, and Hashes will be converted
|
79
|
+
# into Blashes for nesting purposes.
|
80
|
+
def custom_writer(key,value) #:nodoc:
|
81
|
+
regular_writer(convert_key(key), convert_value(value))
|
82
|
+
end
|
83
|
+
|
84
|
+
alias_method :[], :custom_reader
|
85
|
+
alias_method :[]=, :custom_writer
|
86
|
+
|
87
|
+
# This is the bang method reader, it will return a new Blash
|
88
|
+
# if there isn't a value already assigned to the key requested.
|
89
|
+
def initializing_reader(key)
|
90
|
+
ck = convert_key(key)
|
91
|
+
regular_writer(ck, self.class.new) unless key?(ck)
|
92
|
+
regular_reader(ck)
|
93
|
+
end
|
94
|
+
|
95
|
+
def fetch(key, *args)
|
96
|
+
super(convert_key(key), *args)
|
97
|
+
end
|
98
|
+
|
99
|
+
def delete(key)
|
100
|
+
super(convert_key(key))
|
101
|
+
end
|
102
|
+
|
103
|
+
alias_method :regular_dup, :dup
|
104
|
+
# Duplicates the current blash as a new blash.
|
105
|
+
def dup
|
106
|
+
self.class.new(self, self.default)
|
107
|
+
end
|
108
|
+
|
109
|
+
def key?(key)
|
110
|
+
super(convert_key(key))
|
111
|
+
end
|
112
|
+
alias_method :has_key?, :key?
|
113
|
+
alias_method :include?, :key?
|
114
|
+
alias_method :member?, :key?
|
115
|
+
|
116
|
+
# Performs a deep_update on a duplicate of the
|
117
|
+
# current blash.
|
118
|
+
def deep_merge(other_hash, &blk)
|
119
|
+
dup.deep_update(other_hash, &blk)
|
120
|
+
end
|
121
|
+
alias_method :merge, :deep_merge
|
122
|
+
|
123
|
+
# Recursively merges this blash with the passed
|
124
|
+
# in hash, merging each hash in the hierarchy.
|
125
|
+
def deep_update(other_hash, &blk)
|
126
|
+
other_hash.each_pair do |k,v|
|
127
|
+
key = convert_key(k)
|
128
|
+
if regular_reader(key).is_a?(Blash) and v.is_a?(::Hash)
|
129
|
+
custom_reader(key).deep_update(v, &blk)
|
130
|
+
else
|
131
|
+
value = convert_value(v, true)
|
132
|
+
value = blk.call(key, self[k], value) if blk
|
133
|
+
custom_writer(key, value)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
self
|
137
|
+
end
|
138
|
+
alias_method :deep_merge!, :deep_update
|
139
|
+
alias_method :update, :deep_update
|
140
|
+
alias_method :merge!, :update
|
141
|
+
|
142
|
+
# Performs a shallow_update on a duplicate of the current blash
|
143
|
+
def shallow_merge(other_hash)
|
144
|
+
dup.shallow_update(other_hash)
|
145
|
+
end
|
146
|
+
|
147
|
+
# Merges (non-recursively) the hash from the argument,
|
148
|
+
# changing the receiving hash
|
149
|
+
def shallow_update(other_hash)
|
150
|
+
other_hash.each_pair do |k,v|
|
151
|
+
regular_writer(convert_key(k), convert_value(v, true))
|
152
|
+
end
|
153
|
+
self
|
154
|
+
end
|
155
|
+
|
156
|
+
def replace(other_hash)
|
157
|
+
(keys - other_hash.keys).each { |key| delete(key) }
|
158
|
+
other_hash.each { |key, value| self[key] = value }
|
159
|
+
self
|
160
|
+
end
|
161
|
+
|
162
|
+
# Will return true if the Blash has had a key
|
163
|
+
# set in addition to normal respond_to? functionality.
|
164
|
+
def respond_to?(method_name, include_private=false)
|
165
|
+
return true if key?(method_name) || method_name.to_s.slice(/[=?]\Z/)
|
166
|
+
super
|
167
|
+
end
|
168
|
+
|
169
|
+
def method_missing(method_name, *args, &blk)
|
170
|
+
match = method_name.to_s.match(/(.*?)([?=]?)$/)
|
171
|
+
|
172
|
+
if block_given?
|
173
|
+
super unless match[2].empty?
|
174
|
+
|
175
|
+
raise ArgumentError, "wrong number of arguments (#{args.size} for 0)" if args.size > 1
|
176
|
+
|
177
|
+
if key?(method_name) && ! self.[](method_name).is_a?(Blash)
|
178
|
+
raise TypeError, "key '#{method_name}' already contains a #{self.[](method_name).class}"
|
179
|
+
end
|
180
|
+
|
181
|
+
val = self.[](method_name) || initializing_reader(method_name)
|
182
|
+
|
183
|
+
yield val
|
184
|
+
|
185
|
+
return val
|
186
|
+
else
|
187
|
+
if key?(method_name)
|
188
|
+
raise ArgumentError, "wrong number of arguments (#{args.size} for 0)" unless args.empty?
|
189
|
+
return self.[](method_name, &blk)
|
190
|
+
end
|
191
|
+
|
192
|
+
case match[2]
|
193
|
+
when "="
|
194
|
+
raise ArgumentError, "wrong number of arguments (#{args.size} for 1)" unless args.size == 1
|
195
|
+
self[match[1]] = args.first
|
196
|
+
when "?"
|
197
|
+
raise ArgumentError, "wrong number of arguments (#{args.size} for 0)" unless args.empty?
|
198
|
+
!!self[match[1]]
|
199
|
+
when ""
|
200
|
+
raise ArgumentError, "wrong number of arguments (#{args.size} for 0)" unless args.empty?
|
201
|
+
default(method_name)
|
202
|
+
else
|
203
|
+
super
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
protected
|
209
|
+
|
210
|
+
def convert_key(key) #:nodoc:
|
211
|
+
key.to_s
|
212
|
+
end
|
213
|
+
|
214
|
+
def convert_value(val, duping=false) #:nodoc:
|
215
|
+
case val
|
216
|
+
when self.class
|
217
|
+
val.dup
|
218
|
+
when Hash
|
219
|
+
duping ? val.dup : val
|
220
|
+
when ::Hash
|
221
|
+
val = val.dup if duping
|
222
|
+
self.class.new(val)
|
223
|
+
when Array
|
224
|
+
val.collect{ |e| convert_value(e) }
|
225
|
+
else
|
226
|
+
val
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
data/script/bootstrap
ADDED
metadata
ADDED
@@ -0,0 +1,246 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: chaindrive
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- John Bellone
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-09-29 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: thor
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0.18'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0.18'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: multi_json
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '1.0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '1.0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: hashie
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '2.0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: colorize
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0.6'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0.6'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: bundler
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '1.3'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '1.3'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: rake
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: pry
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: pry-debugger
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
- !ruby/object:Gem::Dependency
|
143
|
+
name: pry-stack_explorer
|
144
|
+
requirement: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - ! '>='
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '0'
|
150
|
+
type: :development
|
151
|
+
prerelease: false
|
152
|
+
version_requirements: !ruby/object:Gem::Requirement
|
153
|
+
none: false
|
154
|
+
requirements:
|
155
|
+
- - ! '>='
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0'
|
158
|
+
- !ruby/object:Gem::Dependency
|
159
|
+
name: guard-minitest
|
160
|
+
requirement: !ruby/object:Gem::Requirement
|
161
|
+
none: false
|
162
|
+
requirements:
|
163
|
+
- - ! '>='
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '0'
|
166
|
+
type: :development
|
167
|
+
prerelease: false
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - ! '>='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
description: A tool to describe complex software systems.
|
175
|
+
email:
|
176
|
+
- john.bellone.jr@gmail.com
|
177
|
+
executables:
|
178
|
+
- chaindrive
|
179
|
+
extensions: []
|
180
|
+
extra_rdoc_files: []
|
181
|
+
files:
|
182
|
+
- .gitignore
|
183
|
+
- .ruby-version
|
184
|
+
- .travis.yml
|
185
|
+
- Gemfile
|
186
|
+
- Guardfile
|
187
|
+
- LICENSE.txt
|
188
|
+
- README.md
|
189
|
+
- Rakefile
|
190
|
+
- bin/chaindrive
|
191
|
+
- chaindrive.gemspec
|
192
|
+
- etc/Gearfile
|
193
|
+
- etc/rbenv.gearspec
|
194
|
+
- lib/chaindrive.rb
|
195
|
+
- lib/chaindrive/command.rb
|
196
|
+
- lib/chaindrive/command/config.rb
|
197
|
+
- lib/chaindrive/command/install.rb
|
198
|
+
- lib/chaindrive/command/upgrade.rb
|
199
|
+
- lib/chaindrive/config.rb
|
200
|
+
- lib/chaindrive/environment.rb
|
201
|
+
- lib/chaindrive/gear.rb
|
202
|
+
- lib/chaindrive/gear/provisioner.rb
|
203
|
+
- lib/chaindrive/gear/specification.rb
|
204
|
+
- lib/chaindrive/gearbox.rb
|
205
|
+
- lib/chaindrive/gearbox/isolation.rb
|
206
|
+
- lib/chaindrive/gearbox/specification.rb
|
207
|
+
- lib/chaindrive/index.rb
|
208
|
+
- lib/chaindrive/templates/Gearfile
|
209
|
+
- lib/chaindrive/user.rb
|
210
|
+
- lib/chaindrive/version.rb
|
211
|
+
- lib/hashie/blash.rb
|
212
|
+
- script/bootstrap
|
213
|
+
- spec/chaindrive/user_spec.rb
|
214
|
+
homepage: http://chaindrive.io
|
215
|
+
licenses:
|
216
|
+
- MIT
|
217
|
+
post_install_message:
|
218
|
+
rdoc_options: []
|
219
|
+
require_paths:
|
220
|
+
- lib
|
221
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
222
|
+
none: false
|
223
|
+
requirements:
|
224
|
+
- - ! '>='
|
225
|
+
- !ruby/object:Gem::Version
|
226
|
+
version: '0'
|
227
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
228
|
+
none: false
|
229
|
+
requirements:
|
230
|
+
- - ! '>='
|
231
|
+
- !ruby/object:Gem::Version
|
232
|
+
version: '0'
|
233
|
+
requirements: []
|
234
|
+
rubyforge_project:
|
235
|
+
rubygems_version: 1.8.23
|
236
|
+
signing_key:
|
237
|
+
specification_version: 3
|
238
|
+
summary: ! '# Chaindrive [](http://travis-ci.org/chaindrive/chaindrive)
|
239
|
+
=================================== ## Installation Add this line to your application''s
|
240
|
+
Gemfile: gem ''chaindrive'' And then execute: $ bundle Or install it yourself
|
241
|
+
as: $ gem install chaindrive ## Usage $ chaindrive help ## Contributing 1.
|
242
|
+
Fork it y2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit
|
243
|
+
your changes (`git commit -am ''Add some feature''`) 4. Push to the branch (`git
|
244
|
+
push origin my-new-feature`) 5. Create new Pull Request'
|
245
|
+
test_files:
|
246
|
+
- spec/chaindrive/user_spec.rb
|