asetus-0.3.0/0000755000175000017500000000000012564065713012035 5ustar jonasjonasasetus-0.3.0/README.md0000644000175000017500000000433512564065713013321 0ustar jonasjonas# Asetus Configuration library for ruby with YAML/JSON/TOML backends with unified object access ## Install ``` % gem install asetus ``` ## Use ### Simple ``` require 'asetus' cfg = Asetus.cfg port = cfg.server.port user = cfg.auth.user pw = cfg.auth.password ``` It tried to detect your software name via caller_locations if no ':name' argument was given. It automatically loads /etc/name/config and ~/.config/name/config and merges them together. ### Advanced ``` require 'asetus' asetus = Asetus.new name: 'mykewlapp', default: {'poop'=>'xyzzy'}, adapter: 'yaml', usrdir: '/home/app/config/', sysdir: '/System/config/', load: false asetus.default.poop2 = [1, 2, 3, 4] asetus.default.starship.poopoers = 42 asetus.load :user if asetus.user.empty? asetus.user = asetus.default asetus.save :user end asetus.load # load+merges cfg, takes argument :default, :system, :user asetus.cfg # merged default + system + user (merged on load) asetus.default # default only asetus.system # system only asetus.user # user only ``` ## Reserved methods * each - iterate all config keys in current level * has_key?(arg) - check if current level has key arg * [arg] - fetch arg (useful for non-literal retrieval, instead of using #send) * key? - all keys have question mark version reserved, checks if key exists+true (true), exists+false (false), not-exists (nil) + all object class methods ## TODO * should I add feature to raise on unconfigured/unset? * should I always merge to 'cfg' when default/system/config is set? ## License and Copyright Copyright 2014-2015 Saku Ytti Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. asetus-0.3.0/metadata.yml0000644000175000017500000000217312564065713014343 0ustar jonasjonas--- !ruby/object:Gem::Specification name: asetus version: !ruby/object:Gem::Version version: 0.3.0 platform: ruby authors: - Saku Ytti autorequire: bindir: bin cert_chain: [] date: 2015-03-08 00:00:00.000000000 Z dependencies: [] description: configuration library with object access to YAML/JSON/TOML backends email: - saku@ytti.fi executables: [] extensions: [] extra_rdoc_files: [] files: - ".gitignore" - Gemfile - README.md - Rakefile - asetus.gemspec - lib/asetus.rb - lib/asetus/adapter/json.rb - lib/asetus/adapter/toml.rb - lib/asetus/adapter/yaml.rb - lib/asetus/configstruct.rb homepage: http://github.com/ytti/asetus licenses: - Apache-2.0 metadata: {} post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: asetus rubygems_version: 2.2.2 signing_key: specification_version: 4 summary: configuration library test_files: [] asetus-0.3.0/.gitignore0000644000175000017500000000002212564065713014017 0ustar jonasjonasGemfile.lock gems asetus-0.3.0/lib/0000755000175000017500000000000012564065713012603 5ustar jonasjonasasetus-0.3.0/lib/asetus/0000755000175000017500000000000012564065713014107 5ustar jonasjonasasetus-0.3.0/lib/asetus/configstruct.rb0000644000175000017500000000312112564065713017143 0ustar jonasjonasclass Asetus class ConfigStruct def _asetus_to_hash hash = {} @cfg.each do |key, value| if value.class == ConfigStruct value = value._asetus_to_hash end key = key.to_s if @key_to_s hash[key] = value end hash end def empty? @cfg.empty? end def each &block @cfg.each(&block) end def keys @cfg.keys end def has_key? key @cfg.has_key? key end private def initialize hash=nil, opts={} @key_to_s = opts.delete :key_to_s @cfg = hash ? _asetus_from_hash(hash) : {} end def method_missing name, *args, &block name = name.to_s name = args.shift if name[0..1] == '[]' # asetus.cfg['foo'] arg = args.first if name[-1..-1] == '?' # asetus.cfg.foo.bar? if @cfg.has_key? name[0..-2] @cfg[name[0..-2]] else nil end elsif name[-1..-1] == '=' # asetus.cfg.foo.bar = 'quux' _asetus_set name[0..-2], arg else _asetus_get name, arg # asetus.cfg.foo.bar end end def _asetus_set key, value @cfg[key] = value end def _asetus_get key, value if @cfg.has_key? key @cfg[key] else @cfg[key] = ConfigStruct.new end end def _asetus_from_hash hash cfg = {} hash.each do |key, value| if value.class == Hash value = ConfigStruct.new value, :key_to_s=>@key_to_s end cfg[key] = value end cfg end end end asetus-0.3.0/lib/asetus/adapter/0000755000175000017500000000000012564065713015527 5ustar jonasjonasasetus-0.3.0/lib/asetus/adapter/json.rb0000644000175000017500000000062412564065713017027 0ustar jonasjonasclass Asetus def to_json config Adapter::JSON.to config._asetus_to_hash end def from_json json Adapter::JSON.from json end class Adapter class JSON class << self def to hash require 'json' ::JSON.pretty_generate hash end def from json require 'json' ::JSON.load json end end end end end asetus-0.3.0/lib/asetus/adapter/toml.rb0000644000175000017500000000063112564065713017027 0ustar jonasjonasclass Asetus def to_toml config Adapter::TOML.to config._asetus_to_hash end def from_toml toml Adapter::TOML.from toml end class Adapter class TOML class << self def to hash require 'toml' ::TOML::Generator.new(hash).body end def from toml require 'toml' ::TOML.load toml end end end end end asetus-0.3.0/lib/asetus/adapter/yaml.rb0000644000175000017500000000061112564065713017014 0ustar jonasjonasclass Asetus def to_yaml config Adapter::YAML.to config._asetus_to_hash end def from_yaml yaml Adapter::YAML.from yaml end class Adapter class YAML class << self def to hash require 'yaml' ::YAML.dump hash end def from yaml require 'yaml' ::YAML.load yaml end end end end end asetus-0.3.0/lib/asetus.rb0000644000175000017500000001276612564065713014450 0ustar jonasjonasrequire_relative 'asetus/configstruct' require_relative 'asetus/adapter/yaml' require_relative 'asetus/adapter/json' require_relative 'asetus/adapter/toml' require 'fileutils' class AsetusError < StandardError; end class NoName < AsetusError; end class UnknownOption < AsetusError; end # @example common use case # CFGS = Asetus.new :name=>'my_sweet_program' :load=>false # do not load config from filesystem # CFGS.default.ssh.port = 22 # CFGS.default.ssh.hosts = %w(host1.example.com host2.example.com) # CFGS.default.auth.user = lana # CFGS.default.auth.password = dangerzone # CFGS.load # load system config and user config from filesystem and merge with defaults to #cfg # raise StandardError, 'edit ~/.config/my_sweet_program/config' if CFGS.create # create user config from default config if no system or user config exists # # use the damn thing # CFG = CFGS.cfg # user = CFG.auth.user # password = CFG.auth.password # ssh_port = CFG.ssh.port # ssh_hosts = CFG.ssh.hosts class Asetus CONFIG_FILE = 'config' attr_reader :cfg, :default, :file attr_accessor :system, :user class << self def cfg *args new(*args).cfg end end # When this is called, by default :system and :user are loaded from # filesystem and merged with defefault, so that user overrides system which # overrides default # # @param [Symbol] level which configuration level to load, by defaukt :all # @return [void] def load level=:all if level == :default or level == :all @cfg = merge @cfg, @default end if level == :system or level == :all @system = load_cfg @sysdir @cfg = merge @cfg, @system end if level == :user or level == :all @user = load_cfg @usrdir @cfg = merge @cfg, @user end end # @param [Symbol] level which configuration level to save, by default :user # @return [void] def save level=:user if level == :user save_cfg @usrdir, @user elsif level == :system save_cfg @sysdir, @system end end # @example create user config from default config and raise error, if no config was found # raise StandardError, 'edit ~/.config/name/config' if asetus.create # @param [Hash] opts options for Asetus # @option opts [Symbol] :source source to use for settings to save, by defaylt :default # @option opts [Symbol] :destination destinatino to use for settings to save, by default :user # @option opts [boolean] :load load config once saved, by default false # @return [boolean] true if config didn't exist and was created, false if config already exists def create opts={} src = opts.delete :source src ||= :default dst = opts.delete :destination dst ||= :user no_config = false no_config = true if @system.empty? and @user.empty? if no_config src = instance_variable_get '@' + src.to_s instance_variable_set('@'+dst.to_s, src.dup) save dst load if opts.delete :load end no_config end private # @param [Hash] opts options for Asetus.new # @option opts [String] :name name to use for asetus (/etc/name/, ~/.config/name/) - autodetected if not defined # @option opts [String] :adapter adapter to use 'yaml', 'json' or 'toml' for now # @option opts [String] :usrdir directory for storing user config ~/.config/name/ by default # @option opts [String] :sysdir directory for storing system config /etc/name/ by default # @option opts [String] :cfgfile configuration filename by default CONFIG_FILE # @option opts [Hash] :default default settings to use # @option opts [boolean] :load automatically load+merge system+user config with defaults in #cfg # @option opts [boolean] :key_to_s convert keys to string by calling #to_s for keys def initialize opts={} @name = (opts.delete(:name) or metaname) @adapter = (opts.delete(:adapter) or 'yaml') @usrdir = (opts.delete(:usrdir) or File.join(Dir.home, '.config', @name)) @sysdir = (opts.delete(:sysdir) or File.join('/etc', @name)) @cfgfile = (opts.delete(:cfgfile) or CONFIG_FILE) @default = ConfigStruct.new opts.delete(:default) @system = ConfigStruct.new @user = ConfigStruct.new @cfg = ConfigStruct.new @load = true @load = opts.delete(:load) if opts.has_key?(:load) @key_to_s = opts.delete(:key_to_s) raise UnknownOption, "option '#{opts}' not recognized" unless opts.empty? load :all if @load end def load_cfg dir @file = File.join dir, @cfgfile file = File.read @file ConfigStruct.new(from(@adapter, file), :key_to_s=>@key_to_s) rescue Errno::ENOENT ConfigStruct.new end def save_cfg dir, config config = to(@adapter, config) file = File.join dir, @cfgfile FileUtils.mkdir_p dir File.write file, config end def merge *configs hash = {} configs.each do |config| hash = hash._asetus_deep_merge config._asetus_to_hash end ConfigStruct.new hash end def from adapter, string name = 'from_' + adapter send name, string end def to adapter, config name = 'to_' + adapter send name, config end def metaname path = caller_locations[-1].path File.basename path, File.extname(path) rescue raise NoName, "can't figure out name, specify explicitly" end end class Hash def _asetus_deep_merge newhash merger = proc do |key, oldval, newval| Hash === oldval && Hash === newval ? oldval.merge(newval, &merger) : newval end merge newhash, &merger end end asetus-0.3.0/Gemfile0000644000175000017500000000004712564065713013331 0ustar jonasjonassource 'https://rubygems.org' gemspec asetus-0.3.0/asetus.gemspec0000644000175000017500000000113612564065713014707 0ustar jonasjonasGem::Specification.new do |s| s.name = 'asetus' s.version = '0.3.0' s.licenses = ['Apache-2.0'] s.platform = Gem::Platform::RUBY s.authors = [ 'Saku Ytti' ] s.email = %w( saku@ytti.fi ) s.homepage = 'http://github.com/ytti/asetus' s.summary = 'configuration library' s.description = 'configuration library with object access to YAML/JSON/TOML backends' s.rubyforge_project = s.name s.files = `git ls-files`.split("\n") s.executables = %w( ) s.require_path = 'lib' end asetus-0.3.0/Rakefile0000644000175000017500000000153012564065713013501 0ustar jonasjonasbegin require 'rake/testtask' require 'bundler' #Bundler.setup rescue LoadError warn 'bunler missing' exit 42 end gemspec = eval(File.read(Dir['*.gemspec'].first)) file = [gemspec.name, gemspec.version].join('-') + '.gem' desc 'Validate gemspec' task :gemspec do gemspec.validate end desc 'Run minitest' task :test do Rake::TestTask.new do |t| t.libs.push "lib" t.test_files = FileList['spec/*_spec.rb'] t.verbose = true end end desc 'Build gem' task :build do system "gem build #{gemspec.name}.gemspec" FileUtils.mkdir_p 'gems' FileUtils.mv file, 'gems' end desc 'Install gem' task :install => :build do system "sudo -E sh -c \'umask 022; gem install gems/#{file}\'" end desc 'Remove gems' task :clean do FileUtils.rm_rf 'gems' end desc 'Push to rubygems' task :push do system "gem push gems/#{file}" end