hiera-eyaml 1.1.4 → 1.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +28 -0
- data/PLUGINS.md +4 -0
- data/README.md +51 -41
- data/bin/eyaml +9 -357
- data/features/decrypts.feature +44 -0
- data/features/edit.feature +54 -0
- data/features/encrypts.feature +26 -0
- data/features/keys.feature +13 -0
- data/features/outputs.feature +30 -0
- data/features/plugin.feature +35 -0
- data/features/plugin_api.feature +16 -0
- data/features/puppet.feature +15 -0
- data/features/sandbox/convert_decrypted_values_to_uppercase.sh +2 -0
- data/features/sandbox/keys/private_key.pkcs7.pem +27 -0
- data/features/sandbox/keys/public_key.pkcs7.pem +18 -0
- data/features/sandbox/pipe_string.sh +5 -0
- data/features/sandbox/puppet/environments/local/test.eyaml +3 -0
- data/features/sandbox/puppet/hiera.yaml +17 -0
- data/features/sandbox/puppet/manifests/init.pp +3 -0
- data/features/sandbox/puppet/modules/test/manifests/init.pp +18 -0
- data/features/sandbox/puppet/puppet.conf +6 -0
- data/features/sandbox/supply_password.sh +7 -0
- data/features/sandbox/test_input.bin +0 -0
- data/features/sandbox/test_input.encrypted.txt +1 -0
- data/features/sandbox/test_input.txt +3 -0
- data/features/sandbox/test_input.yaml +114 -0
- data/features/step_definitions/environment_overrides.rb +3 -0
- data/features/support/env.rb +26 -0
- data/features/support/setup_sandbox.rb +21 -0
- data/features/valid_encryption.feature +12 -0
- data/hiera-eyaml.gemspec +1 -1
- data/lib/hiera/backend/eyaml.rb +19 -0
- data/lib/hiera/backend/eyaml/CLI.rb +110 -0
- data/lib/hiera/backend/eyaml/actions/createkeys_action.rb +24 -0
- data/lib/hiera/backend/eyaml/actions/decrypt_action.rb +67 -0
- data/lib/hiera/backend/eyaml/actions/edit_action.rb +47 -0
- data/lib/hiera/backend/eyaml/actions/encrypt_action.rb +80 -0
- data/lib/hiera/backend/eyaml/encryptor.rb +71 -0
- data/lib/hiera/backend/eyaml/encryptors/pkcs7.rb +99 -0
- data/lib/hiera/backend/eyaml/options.rb +32 -0
- data/lib/hiera/backend/eyaml/plugins.rb +65 -0
- data/lib/hiera/backend/eyaml/utils.rb +83 -0
- data/lib/hiera/backend/eyaml_backend.rb +108 -113
- data/sublime_text/README.md +16 -0
- data/sublime_text/eyaml.sublime-package +0 -0
- data/sublime_text/eyaml.syntax_definition.json +288 -0
- data/{bin → tools}/regem.sh +1 -1
- metadata +71 -7
- data/keys/.keepme +0 -0
- data/lib/hiera/backend/version.rb +0 -7
@@ -0,0 +1,26 @@
|
|
1
|
+
ENV['RUBYLIB'] = File.dirname(__FILE__) + '/../../lib'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'aruba/config'
|
4
|
+
require 'aruba/cucumber'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'rspec/expectations'
|
7
|
+
|
8
|
+
test_files = {}
|
9
|
+
Dir["features/sandbox/**/*"].each do |file_name|
|
10
|
+
next unless File.file? file_name
|
11
|
+
read_mode = "r"
|
12
|
+
read_mode = "rb" if file_name =~ /\.bin$/
|
13
|
+
file = File.open(file_name, "r")
|
14
|
+
file_contents = file.read
|
15
|
+
file.close
|
16
|
+
file_name = file_name.slice(17, file_name.length)
|
17
|
+
test_files[file_name] = file_contents
|
18
|
+
end
|
19
|
+
|
20
|
+
# ENV['EDITOR']="/bin/cat"
|
21
|
+
|
22
|
+
Aruba.configure do |config|
|
23
|
+
config.before_cmd do |cmd|
|
24
|
+
SetupSandbox.create_files test_files
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
class SetupSandbox
|
4
|
+
|
5
|
+
def self.create_files test_files
|
6
|
+
|
7
|
+
test_files.each do |test_file, contents|
|
8
|
+
extension = test_file.split('.').last
|
9
|
+
target_dir = File.dirname(test_file)
|
10
|
+
FileUtils.mkdir_p( target_dir ) unless Dir.exists?( target_dir )
|
11
|
+
write_mode = "w"
|
12
|
+
write_mode = "wb" if extension == "bin"
|
13
|
+
File.open(test_file, write_mode) {|input_file|
|
14
|
+
input_file.puts contents
|
15
|
+
} unless File.exists?( test_file )
|
16
|
+
File.chmod(0755, test_file) if extension == "sh"
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
Feature: eyaml encrypting is valid
|
2
|
+
|
3
|
+
Scenario: encrypt and decrypt a binary file
|
4
|
+
When I run `bash -c "eyaml -e -o string -f test_input.bin > test_output.txt"`
|
5
|
+
When I run `bash -c "eyaml -d -f test_output.txt > test_output.bin"`
|
6
|
+
When I run `file test_output.bin`
|
7
|
+
Then the output should match /PNG image data/
|
8
|
+
|
9
|
+
Scenario: encrypt and decrypt a simple file
|
10
|
+
When I run `bash -c "eyaml -e -o string -f test_input.txt > test_output.txt"`
|
11
|
+
When I run `eyaml -d -f test_output.txt`
|
12
|
+
Then the output should match /fox jumped over/
|
data/hiera-eyaml.gemspec
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
class Hiera
|
2
|
+
module Backend
|
3
|
+
module Eyaml
|
4
|
+
|
5
|
+
VERSION = "1.3.1"
|
6
|
+
|
7
|
+
def self.default_encryption_scheme= new_encryption
|
8
|
+
@@default_encryption_scheme = new_encryption
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.default_encryption_scheme
|
12
|
+
@@default_encryption_scheme ||= "PKCS7"
|
13
|
+
@@default_encryption_scheme
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'trollop'
|
2
|
+
require 'hiera/backend/eyaml'
|
3
|
+
require 'hiera/backend/eyaml/utils'
|
4
|
+
require 'hiera/backend/eyaml/actions/createkeys_action'
|
5
|
+
require 'hiera/backend/eyaml/actions/decrypt_action'
|
6
|
+
require 'hiera/backend/eyaml/actions/encrypt_action'
|
7
|
+
require 'hiera/backend/eyaml/actions/edit_action'
|
8
|
+
require 'hiera/backend/eyaml/plugins'
|
9
|
+
require 'hiera/backend/eyaml/options'
|
10
|
+
|
11
|
+
class Hiera
|
12
|
+
module Backend
|
13
|
+
module Eyaml
|
14
|
+
class CLI
|
15
|
+
|
16
|
+
def self.parse
|
17
|
+
|
18
|
+
options = Trollop::options do
|
19
|
+
|
20
|
+
version "Hiera-eyaml version " + Hiera::Backend::Eyaml::VERSION.to_s
|
21
|
+
banner <<-EOS
|
22
|
+
Hiera-eyaml is a backend for Hiera which provides OpenSSL encryption/decryption for Hiera properties
|
23
|
+
|
24
|
+
Usage:
|
25
|
+
eyaml [options]
|
26
|
+
eyaml -i file.eyaml # edit a file
|
27
|
+
eyaml -e -s some-string # encrypt a string
|
28
|
+
eyaml -e -p # encrypt a password
|
29
|
+
eyaml -e -f file.txt # encrypt a file
|
30
|
+
cat file.txt | eyaml -e # encrypt a file on a pipe
|
31
|
+
|
32
|
+
Options:
|
33
|
+
EOS
|
34
|
+
|
35
|
+
opt :createkeys, "Create public and private keys for use encrypting properties", :short => 'c'
|
36
|
+
opt :decrypt, "Decrypt something"
|
37
|
+
opt :encrypt, "Encrypt something"
|
38
|
+
opt :edit, "Decrypt, Edit, and Reencrypt", :type => :string
|
39
|
+
opt :eyaml, "Source input is an eyaml file", :type => :string
|
40
|
+
opt :password, "Source input is a password entered on the terminal", :short => 'p'
|
41
|
+
opt :string, "Source input is a string provided as an argument", :short => 's', :type => :string
|
42
|
+
opt :file, "Source input is a file", :short => 'f', :type => :string
|
43
|
+
opt :stdin, "Source input it taken from stdin", :short => 'z'
|
44
|
+
opt :encrypt_method, "Override default encryption and decryption method (default is PKCS7)", :short => 'n', :default => "pkcs7"
|
45
|
+
opt :output, "Output format of final result (examples, block, string)", :type => :string, :default => "examples"
|
46
|
+
|
47
|
+
Hiera::Backend::Eyaml::Plugins.options.each do |name, option|
|
48
|
+
opt name, option[:desc], :type => option[:type], :short => option[:short], :default => option[:default]
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
actions = [:createkeys, :decrypt, :encrypt, :edit].collect {|x| x if options[x]}.compact
|
54
|
+
sources = [:edit, :eyaml, :password, :string, :file, :stdin].collect {|x| x if options[x]}.compact
|
55
|
+
# sources << :stdin if STDIN
|
56
|
+
|
57
|
+
Trollop::die "You can only specify one of (#{actions.join(', ')})" if actions.count > 1
|
58
|
+
Trollop::die "You can only specify one of (#{sources.join(', ')})" if sources.count > 1
|
59
|
+
Trollop::die "Creating keys does not require a source to encrypt/decrypt" if actions.first == :createkeys and sources.count > 0
|
60
|
+
|
61
|
+
options[:source] = sources.first
|
62
|
+
options[:action] = actions.first
|
63
|
+
options[:source] = :not_applicable if options[:action] == :createkeys
|
64
|
+
|
65
|
+
Trollop::die "Nothing to do" if options[:source].nil? or options[:action].nil?
|
66
|
+
|
67
|
+
options[:input_data] = case options[:source]
|
68
|
+
when :stdin
|
69
|
+
STDIN.read
|
70
|
+
when :password
|
71
|
+
Utils.read_password
|
72
|
+
when :string
|
73
|
+
options[:string]
|
74
|
+
when :file
|
75
|
+
File.read options[:file]
|
76
|
+
when :eyaml
|
77
|
+
File.read options[:eyaml]
|
78
|
+
when :stdin
|
79
|
+
STDIN.read
|
80
|
+
else
|
81
|
+
if options[:edit]
|
82
|
+
options[:eyaml] = options[:edit]
|
83
|
+
options[:source] = :eyaml
|
84
|
+
File.read options[:edit]
|
85
|
+
else
|
86
|
+
nil
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
Eyaml.default_encryption_scheme = options[:encrypt_method].upcase if options[:encrypt_method]
|
91
|
+
Eyaml::Options.set options
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.execute
|
96
|
+
|
97
|
+
action = Eyaml::Options[:action]
|
98
|
+
action_class = Module.const_get('Hiera').const_get('Backend').const_get('Eyaml').const_get('Actions').const_get("#{Utils.camelcase action.to_s}Action")
|
99
|
+
|
100
|
+
puts action_class.execute
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'hiera/backend/eyaml/utils'
|
2
|
+
require 'hiera/backend/eyaml/options'
|
3
|
+
|
4
|
+
class Hiera
|
5
|
+
module Backend
|
6
|
+
module Eyaml
|
7
|
+
module Actions
|
8
|
+
|
9
|
+
class CreatekeysAction
|
10
|
+
|
11
|
+
def self.execute
|
12
|
+
|
13
|
+
encryptor = Encryptor.find Eyaml.default_encryption_scheme
|
14
|
+
encryptor.create_keys
|
15
|
+
nil
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'hiera/backend/eyaml/utils'
|
2
|
+
require 'hiera/backend/eyaml/options'
|
3
|
+
|
4
|
+
class Hiera
|
5
|
+
module Backend
|
6
|
+
module Eyaml
|
7
|
+
module Actions
|
8
|
+
|
9
|
+
class DecryptAction
|
10
|
+
|
11
|
+
REGEX_ENCRYPTED_BLOCK = />\n(\s*)ENC\[(\w+,)?([a-zA-Z0-9\+\/ =\n]+)\]/
|
12
|
+
REGEX_ENCRYPTED_STRING = /ENC\[(\w+,)?([a-zA-Z0-9\+\/=]+)\]/
|
13
|
+
|
14
|
+
def self.execute
|
15
|
+
|
16
|
+
output_data = case Eyaml::Options[:source]
|
17
|
+
when :eyaml
|
18
|
+
encryptions = []
|
19
|
+
|
20
|
+
# blocks
|
21
|
+
output = Eyaml::Options[:input_data].gsub( REGEX_ENCRYPTED_BLOCK ) { |match|
|
22
|
+
indentation = $1
|
23
|
+
encryption_scheme = parse_encryption_scheme( $2 )
|
24
|
+
decryptor = Encryptor.find encryption_scheme
|
25
|
+
ciphertext = $3.gsub(/[ \n]/, '')
|
26
|
+
plaintext = decryptor.decrypt( decryptor.decode ciphertext )
|
27
|
+
">\n" + indentation + "DEC::#{decryptor.tag}[" + plaintext + "]!"
|
28
|
+
}
|
29
|
+
|
30
|
+
# strings
|
31
|
+
output.gsub!( REGEX_ENCRYPTED_STRING ) { |match|
|
32
|
+
encryption_scheme = parse_encryption_scheme( $1 )
|
33
|
+
decryptor = Encryptor.find encryption_scheme
|
34
|
+
|
35
|
+
plaintext = decryptor.decrypt( decryptor.decode $2 )
|
36
|
+
"DEC::#{decryptor.tag}[" + plaintext + "]!"
|
37
|
+
}
|
38
|
+
|
39
|
+
output
|
40
|
+
else
|
41
|
+
|
42
|
+
output = Eyaml::Options[:input_data].gsub( REGEX_ENCRYPTED_STRING ) { |match|
|
43
|
+
encryption_scheme = parse_encryption_scheme( $1 )
|
44
|
+
decryptor = Encryptor.find encryption_scheme
|
45
|
+
decryptor.decrypt( decryptor.decode $2 )
|
46
|
+
}
|
47
|
+
|
48
|
+
output
|
49
|
+
end
|
50
|
+
|
51
|
+
output_data
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
protected
|
56
|
+
|
57
|
+
def self.parse_encryption_scheme regex_result
|
58
|
+
regex_result = Eyaml.default_encryption_scheme + "," if regex_result.nil?
|
59
|
+
regex_result.split(",").first
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'hiera/backend/eyaml/utils'
|
2
|
+
require 'hiera/backend/eyaml/actions/decrypt_action'
|
3
|
+
require 'hiera/backend/eyaml/actions/encrypt_action'
|
4
|
+
require 'hiera/backend/eyaml/options'
|
5
|
+
|
6
|
+
class Hiera
|
7
|
+
module Backend
|
8
|
+
module Eyaml
|
9
|
+
module Actions
|
10
|
+
|
11
|
+
class EditAction
|
12
|
+
|
13
|
+
def self.execute
|
14
|
+
|
15
|
+
decrypted_input = DecryptAction.execute
|
16
|
+
decrypted_file = Utils.write_tempfile decrypted_input
|
17
|
+
editor = Utils.find_editor
|
18
|
+
system editor, decrypted_file
|
19
|
+
status = $?
|
20
|
+
raise StandardError, "Editor #{editor} has not exited?" unless status.exited?
|
21
|
+
raise StandardError, "Editor did not exit successfully (exit code #{status.exitstatus}), aborting" unless status.exitstatus #TODO: The file is left on the disk
|
22
|
+
raise StandardError, "File was moved by editor" unless File.file? decrypted_file
|
23
|
+
|
24
|
+
edited_file = File.read decrypted_file
|
25
|
+
Utils.secure_file_delete :file => decrypted_file, :num_bytes => [edited_file.length, decrypted_input.length].max
|
26
|
+
raise StandardError, "Edited file is blank" if edited_file.empty?
|
27
|
+
raise StandardError, "No changes" if edited_file == decrypted_input
|
28
|
+
|
29
|
+
Eyaml::Options[:input_data] = edited_file
|
30
|
+
Eyaml::Options[:output] = "raw"
|
31
|
+
|
32
|
+
encrypted_output = EncryptAction.execute
|
33
|
+
|
34
|
+
filename = Eyaml::Options[:eyaml]
|
35
|
+
File.open("#{filename}", 'w') { |file|
|
36
|
+
file.write encrypted_output
|
37
|
+
}
|
38
|
+
|
39
|
+
true
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'hiera/backend/eyaml/options'
|
2
|
+
|
3
|
+
class Hiera
|
4
|
+
module Backend
|
5
|
+
module Eyaml
|
6
|
+
module Actions
|
7
|
+
|
8
|
+
class EncryptAction
|
9
|
+
|
10
|
+
REGEX_DECRYPTED_BLOCK = />\n(\s*)DEC(::\w+)?\[(.+)\]\!/
|
11
|
+
REGEX_DECRYPTED_STRING = /DEC(::\w+)?\[(.+)\]\!/
|
12
|
+
|
13
|
+
def self.execute
|
14
|
+
|
15
|
+
output_data = case Eyaml::Options[:source]
|
16
|
+
when :eyaml
|
17
|
+
encryptions = []
|
18
|
+
|
19
|
+
# blocks
|
20
|
+
output = Eyaml::Options[:input_data].gsub( REGEX_DECRYPTED_BLOCK ) { |match|
|
21
|
+
indentation = $1
|
22
|
+
encryption_scheme = parse_encryption_scheme( $2 )
|
23
|
+
encryptor = Encryptor.find encryption_scheme
|
24
|
+
ciphertext = encryptor.encode( encryptor.encrypt($3) ).gsub(/\n/, "\n" + indentation)
|
25
|
+
">\n" + indentation + "ENC[#{encryptor.tag},#{ciphertext}]"
|
26
|
+
}
|
27
|
+
|
28
|
+
# strings
|
29
|
+
output.gsub!( REGEX_DECRYPTED_STRING ) { |match|
|
30
|
+
encryption_scheme = parse_encryption_scheme( $1 )
|
31
|
+
encryptor = Encryptor.find encryption_scheme
|
32
|
+
ciphertext = encryptor.encode( encryptor.encrypt($2) ).gsub(/\n/, "")
|
33
|
+
"ENC[#{encryptor.tag},#{ciphertext}]"
|
34
|
+
}
|
35
|
+
|
36
|
+
else
|
37
|
+
encryptor = Encryptor.find
|
38
|
+
ciphertext = encryptor.encode( encryptor.encrypt(Eyaml::Options[:input_data]) )
|
39
|
+
"ENC[#{encryptor.tag},#{ciphertext}]"
|
40
|
+
end
|
41
|
+
|
42
|
+
self.format :data => output_data, :structure => Eyaml::Options[:output]
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
protected
|
47
|
+
|
48
|
+
def self.parse_encryption_scheme regex_result
|
49
|
+
regex_result = "::" + Eyaml.default_encryption_scheme if regex_result.nil?
|
50
|
+
regex_result.split("::").last
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.format args
|
54
|
+
data = args[:data]
|
55
|
+
data_as_block = data.split("\n").join("\n ")
|
56
|
+
data_as_string = data.split("\n").join("")
|
57
|
+
structure = args[:structure]
|
58
|
+
|
59
|
+
case structure
|
60
|
+
when "examples"
|
61
|
+
"string: #{data_as_string}\n\n" +
|
62
|
+
"OR\n\n" +
|
63
|
+
"block: >\n" +
|
64
|
+
" #{data_as_block}"
|
65
|
+
when "block"
|
66
|
+
" #{data_as_block}"
|
67
|
+
when "string"
|
68
|
+
"#{data_as_string}"
|
69
|
+
else
|
70
|
+
data.to_s
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
class Hiera
|
4
|
+
module Backend
|
5
|
+
module Eyaml
|
6
|
+
|
7
|
+
class Encryptor
|
8
|
+
|
9
|
+
class << self
|
10
|
+
attr_accessor :options
|
11
|
+
attr_accessor :tag
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.find encryption_scheme = nil
|
15
|
+
encryption_scheme = Eyaml.default_encryption_scheme if encryption_scheme.nil?
|
16
|
+
require "hiera/backend/eyaml/encryptors/#{encryption_scheme.downcase}"
|
17
|
+
encryptor_module = Module.const_get('Hiera').const_get('Backend').const_get('Eyaml').const_get('Encryptors')
|
18
|
+
encryptor_class = self.find_closest_class :parent_class => encryptor_module, :class_name => encryption_scheme
|
19
|
+
raise StandardError, "Could not find hiera-eyaml encryptor: #{encryption_scheme}. Try gem install hiera-eyaml-#{encryption_scheme.downcase} ?" if encryptor_class.nil?
|
20
|
+
encryptor_class
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.encode binary_string
|
24
|
+
Base64.encode64(binary_string).strip
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.decode string
|
28
|
+
Base64.decode64(string)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.encrypt *args
|
32
|
+
raise StandardError, "encrypt() not defined for encryptor plugin: #{self}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.decrypt *args
|
36
|
+
raise StandardError, "decrypt() not defined for decryptor plugin: #{self}"
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
def self.register
|
42
|
+
plugin_classname = self.to_s.split("::").last.downcase
|
43
|
+
Hiera::Backend::Eyaml::Plugins.register_options :options => self.options, :plugin => plugin_classname
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.option name
|
47
|
+
plugin_classname = self.to_s.split("::").last.downcase
|
48
|
+
Eyaml::Options[ "#{plugin_classname}_#{name}" ] || self.options[ "#{plugin_classname}_#{name}" ]
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.find_closest_class args
|
52
|
+
parent_class = args[ :parent_class ]
|
53
|
+
class_name = args[ :class_name ]
|
54
|
+
constants = parent_class.constants
|
55
|
+
candidates = []
|
56
|
+
constants.each do | candidate |
|
57
|
+
candidates << candidate.to_s if candidate.to_s.downcase == class_name.downcase
|
58
|
+
end
|
59
|
+
if candidates.count > 0
|
60
|
+
parent_class.const_get candidates.first
|
61
|
+
else
|
62
|
+
nil
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|