Top Level Namespace
Defined Under Namespace
Modules: Deject
Instance Method Summary collapse
Instance Method Details
#Deject(klass, *initial_dependencies) ⇒ Object
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/deject.rb', line 30 def Deject(klass, *initial_dependencies) # Not a common way of writing code in Ruby, I know. # But I tried out several implementations and found this was the easiest to # work with within the constraints of the gem (that it doesn't leave traces # of itself all over your objects) uninitialized_error = lambda do |meth| raise Deject::UninitializedDependency, "#{meth} invoked before being defined" end define_instance_methods = lambda do |meth, default_block| # define the getter define_method meth do block = default_block || Deject.registered(meth) uninitialized_error[meth] unless block value = block.call self define_singleton_method(meth) { value } send meth end # define the override define_method :"with_#{meth}" do |value=nil, &block| # redefine getter if given a block if block define_singleton_method meth do value = block.call self define_singleton_method(meth) { value } send meth end # always return value if given a value else define_singleton_method(meth) { value } end self end self end has_dependency = lambda do |meth| instance_methods.include?(meth.intern) && instance_methods.include?(:"with_#{meth}") end # define klass.dependency klass.define_singleton_method :dependency do |meth, &default_block| if instance_exec meth, &has_dependency warn "Deprecation: Use .override instead of .dependency to override a dependency (#{meth})" end instance_exec meth, default_block, &define_instance_methods end # define klass.override klass.define_singleton_method :override do |meth, &override_block| if !override_block raise ArgumentError, "Cannot override #{meth} without an override block" unless override_block elsif !instance_exec(meth, &has_dependency) raise ArgumentError, "#{meth} is not a dependency of #{klass.inspect}" else instance_exec meth, override_block, &define_instance_methods end end # override multiple dependencies klass.send :define_method, :with_dependencies do |overrides| overrides.each { |meth, value| send "with_#{meth}", value } self end # add the initial dependencies initial_dependencies.each { |dependency| klass.dependency dependency } klass end |