needs_resources 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
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source :rubygems
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013, David McCullars
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.
@@ -0,0 +1,4 @@
1
+ needs_resources
2
+ ===============
3
+
4
+ A lightweight Inversion of Control provider of resources for an application
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,35 @@
1
+ require 'set'
2
+ require 'active_support'
3
+ require 'active_support/core_ext'
4
+
5
+ module NeedsResources
6
+
7
+ def needs_resources(*names)
8
+ container = is_a?(ResourceContainer) ? self : TopLevelResources.instance
9
+ names.flatten.each do |name|
10
+ if is_a? Class
11
+ define_method name, lambda { container[name] }
12
+ end
13
+ define_singleton_method name, lambda { container[name] }
14
+ container.resources_needed << name.to_sym
15
+ end
16
+ end
17
+
18
+ alias :needs_resource :needs_resources
19
+
20
+ def self.ensure_resources
21
+ if (missing = missing_resources).present?
22
+ # TODO: maybe prompt user if missing?
23
+ raise MissingResourceError.new(*missing)
24
+ end
25
+ end
26
+
27
+ def self.missing_resources
28
+ TopLevelResources.instance.missing_resources
29
+ end
30
+
31
+ end
32
+
33
+ Dir[File.expand_path('../needs_resources/**/*.rb', __FILE__)].sort.each do |f|
34
+ require f
35
+ end
@@ -0,0 +1,9 @@
1
+ module NeedsResources
2
+ class InvalidOrCorruptedResourcesError < StandardError
3
+
4
+ def initialize
5
+ super "Invalid or corrupted resources config file"
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module NeedsResources
2
+ class InvalidResourceAliasError < StandardError
3
+
4
+ def initialize(name)
5
+ super "Invalid resource alias in config file: #{name.inspect}"
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module NeedsResources
2
+ class InvalidResourceKeyError < StandardError
3
+
4
+ def initialize(name)
5
+ super "Invalid resource key in config file: #{name.inspect}"
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module NeedsResources
2
+ class InvalidResourceValueError < StandardError
3
+
4
+ def initialize(name, value)
5
+ super "Invalid resource value in config file for #{name.inspect}: #{value.inspect}"
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ module NeedsResources
2
+ class MissingResourceError < StandardError
3
+
4
+ def initialize(*names)
5
+ if names.size == 1
6
+ super "The following resources is missing: #{names.first}."
7
+ else
8
+ super "The following resources are missing: #{names.to_sentence}."
9
+ end
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module NeedsResources
2
+ module NestedResourceType
3
+
4
+ def self.included(base)
5
+ base.send :include, ResourceType
6
+ base.send :include, ResourceContainer
7
+ base.send :include, NeedsResources
8
+
9
+ base.attr :resources, :default => {}
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ module NeedsResources
2
+ class RequiredAttributeError < StandardError
3
+
4
+ def initialize(clazz, name)
5
+ super "Missing resource in config file: #{clazz} (in #{name})"
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,42 @@
1
+ module NeedsResources
2
+ module ResourceContainer
3
+
4
+ def [](name)
5
+ resources[name] or raise MissingResourceError.new(child_resource_name name)
6
+ end
7
+
8
+ def child_resource_name(child_name)
9
+ if respond_to?(:name)
10
+ "#{self.name}.#{child_name}"
11
+ else
12
+ child_name.to_s
13
+ end
14
+ end
15
+
16
+ def resources
17
+ @resources ||= {}.with_indifferent_access
18
+ end
19
+
20
+ def resources_needed
21
+ @resources_needed ||= Set.new
22
+ end
23
+
24
+ def missing_resources
25
+ __missing_resources__(missing = {})
26
+ missing.map do |k, v|
27
+ k.child_resource_name(v)
28
+ end.sort
29
+ end
30
+
31
+ def __missing_resources__(missing)
32
+ resources_needed.each do |name|
33
+ if !resources[name]
34
+ missing[self] = name
35
+ elsif resources[name].is_a? ResourceContainer
36
+ resources[name].__missing_resources__(missing)
37
+ end
38
+ end
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,42 @@
1
+ module NeedsResources
2
+ module ResourceType
3
+
4
+ def self.included(base)
5
+ children[base.name.demodulize.underscore] = base
6
+ base.instance_eval do
7
+ def attr(*names)
8
+ options = names.last.is_a?(Hash) ? names.pop : {}
9
+ names.flatten.each do |n|
10
+ attributes[n] = options.with_indifferent_access
11
+ attr_reader n
12
+ end
13
+ end
14
+
15
+ def attributes
16
+ @attributes ||= {}.with_indifferent_access
17
+ end
18
+ end
19
+ base.attr :name, :required => true
20
+ end
21
+
22
+ def self.children
23
+ @children ||= {}
24
+ end
25
+
26
+ def initialize(args={})
27
+ args = args.with_indifferent_access
28
+ self.class.attributes.each do |name, options|
29
+ value = args.delete(name) || options[:default]
30
+ if options[:required] && value.nil?
31
+ raise RequiredAttributeError.new(self, name)
32
+ end
33
+ value = value.with_indifferent_access if value.is_a? Hash
34
+ instance_variable_set "@#{name}", value
35
+ end
36
+ args.each do |k, v|
37
+ warn "Invalid initializer argument (#{k.inspect}) for class #{self}"
38
+ end
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,85 @@
1
+ require 'singleton'
2
+ require 'yaml'
3
+
4
+ module NeedsResources
5
+ class TopLevelResources
6
+
7
+ include Singleton
8
+ include ResourceContainer
9
+
10
+ private
11
+
12
+ def resources
13
+ @resources ||= parse(resource_config_file)
14
+ end
15
+
16
+ def resource_config_file
17
+ Dir[ENV['RESOURCES'].to_s, File.expand_path('~/.resources'), '.resources'].first
18
+ end
19
+
20
+ def parse(file)
21
+ resources = {}.with_indifferent_access
22
+ return resources unless File.exist? file
23
+
24
+ yaml = YAML.load_file(file)
25
+ raise InvalidOrCorruptedResources unless yaml.is_a? Hash
26
+
27
+ yaml.each do |name, value|
28
+ prefix, type = parse_resource_name(name)
29
+ resources[name] = parse_resource_value(name, type, value)
30
+
31
+ # Make sure both default_xyz and xyz are aliases
32
+ if prefix == 'default_'
33
+ resources[type] ||= name.to_sym
34
+ elsif prefix.nil?
35
+ resources[type] ||= "default_#{type}".to_sym
36
+ end
37
+ end
38
+
39
+ # Copy symbol aliases
40
+ resources.each do |name, value|
41
+ resources[name] = dereference_alias(resources, name, value) or raise InvalidResourceAliasError.new(value)
42
+ end
43
+
44
+ resources
45
+ end
46
+
47
+ def top_level_names
48
+ ResourceType.children.keys
49
+ end
50
+
51
+ def parse_resource_name(name)
52
+ if m = /^(.*_)?(#{top_level_names * '|'})$/.match(name)
53
+ m[1..2]
54
+ else
55
+ raise InvalidResourceKeyError.new(name)
56
+ end
57
+ end
58
+
59
+ def parse_resource_value(name, type, value)
60
+ case value
61
+ when Symbol
62
+ value
63
+ when Hash
64
+ ResourceType.children[type].new(value.merge :name => name)
65
+ else
66
+ raise InvalidResourceValueError.new(name, value)
67
+ end
68
+ end
69
+
70
+ def dereference_alias(hash, name, value)
71
+ considered = Set.new
72
+ while value.is_a?(Symbol) and !considered.include?(value)
73
+ considered << name
74
+ name = value
75
+ value = hash[value]
76
+ end
77
+ value
78
+ end
79
+
80
+ def to_s
81
+ "Top Level Resources"
82
+ end
83
+
84
+ end
85
+ end
@@ -0,0 +1,3 @@
1
+ module NeedsResources
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/needs_resources/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["David McCullars"]
6
+ gem.email = ["david.mccullars@gmail.com"]
7
+ gem.description = %q{Ruby gem to provide lightweight inversion of control type resources for an application}
8
+ gem.summary = %q{Ruby gem to provide lightweight inversion of control type resources for an application}
9
+ gem.homepage = ""
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "needs_resources"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = NeedsResources::VERSION
17
+
18
+ gem.add_dependency('active_support', '> 2.0')
19
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: needs_resources
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - David McCullars
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-10-28 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: active_support
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>'
20
+ - !ruby/object:Gem::Version
21
+ version: '2.0'
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: '2.0'
30
+ description: Ruby gem to provide lightweight inversion of control type resources for
31
+ an application
32
+ email:
33
+ - david.mccullars@gmail.com
34
+ executables: []
35
+ extensions: []
36
+ extra_rdoc_files: []
37
+ files:
38
+ - .gitignore
39
+ - Gemfile
40
+ - LICENSE
41
+ - README.md
42
+ - Rakefile
43
+ - lib/needs_resources.rb
44
+ - lib/needs_resources/invalid_or_corrupted_resources_error.rb
45
+ - lib/needs_resources/invalid_resource_alias_error.rb
46
+ - lib/needs_resources/invalid_resource_key_error.rb
47
+ - lib/needs_resources/invalid_resource_value_error.rb
48
+ - lib/needs_resources/missing_resource_error.rb
49
+ - lib/needs_resources/nested_resource_type.rb
50
+ - lib/needs_resources/required_attribute_error.rb
51
+ - lib/needs_resources/resource_container.rb
52
+ - lib/needs_resources/resource_type.rb
53
+ - lib/needs_resources/top_level_resources.rb
54
+ - lib/needs_resources/version.rb
55
+ - needs_resources.gemspec
56
+ homepage: ''
57
+ licenses: []
58
+ post_install_message:
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ! '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubyforge_project:
76
+ rubygems_version: 1.8.24
77
+ signing_key:
78
+ specification_version: 3
79
+ summary: Ruby gem to provide lightweight inversion of control type resources for an
80
+ application
81
+ test_files: []