::Myco::BasicDecorators << {

[decorators]

# The 'const' decorator evaluates immediately and creates a thunk method
const: ConstDecorator
ConstDecorator: Decorator {
  apply: |meme| {
    meme.body = Rubinius::Thunk.new(meme.result)
  }
}

# The 'storage' decorator acts like a set of var decorators
# TODO: consolidate with 'var'
const storage: Decorator {
  # Create a corresponding "writer" meme to go with this "reader" meme
  apply: |meme| {
    meme.target.declare_meme(:""meme.name"=") |new_value, *args| {
      meme.set_result_for(self, new_value, *args)
    }
  }

  [transforms]
  cache: true # Enable caching of the value to act as storage
}

# TODO: add const decorator to make all of these decorators 'thunks'

# The 'var' decorator creates an instance variable getter and setter:
const var: Decorator {
  [transforms]
  var: true
}

# The 'memoize' decorator enables caching of the result
const memoize: Decorator {
  [transforms]
  cache: true
}

# The 'static' decorator makes the component's singleton class the target
const static: Decorator {
  [transforms]
  target: |meme| meme.target.singleton_class
}

# The 'before' decorator defines a wrapper that runs before the existing meme
const before: Decorator {
  apply: |meme| {
    orig_meme = meme.target.memes[meme.name]
    wrap_meme = meme.dup
    meme.body = &|*a,&b| {
      wrap_meme.result_for(self,*a,&b)
      orig_meme.result_for(self,*a,&b)
    }
  }
}

# The 'after' decorator defines a wrapper that runs after the existing meme
const after: Decorator {
  apply: |meme| {
    orig_meme = meme.target.memes[meme.name]
    wrap_meme = meme.dup
    meme.body = &|*a,&b| {
      result = \
      orig_meme.result_for(self,*a,&b)
      wrap_meme.result_for(self,*a,&b)
      result
    }
  }
}

# The 'pre' decorator defines a wrapper that pre-processes arguments
const pre: Decorator {
  apply: |meme| {
    orig_meme = meme.target.memes[meme.name]
    wrap_meme = meme.dup
    meme.body = &|*a,&b| {
      new_a = \
      wrap_meme.result_for(self,*a)
      orig_meme.result_for(self,*new_a,&b)
    }
  }
}

# The 'post' decorator defines a wrapper that post-processes return value
const post: Decorator {
  apply: |meme| {
    orig_meme = meme.target.memes[meme.name]
    wrap_meme = meme.dup
    meme.body = &|*a,&b| {
      result = \
      orig_meme.result_for(self,*a,&b)
      wrap_meme.result_for(self,result)
    }
  }
}

# The 'setter' decorator defines a setter that pre-processes the given value
const setter: Decorator {
  apply: |meme| {
    wrap_meme = meme.dup
    meme.setter = &|orig_value| {
      wrap_meme.result_for(self,orig_value)
    }
  }
}

# The 'getter' decorator defines a getter that post-processes the return value
const getter: Decorator {
  apply: |meme| {
    wrap_meme = meme.dup
    meme.getter = &|orig_value| {
      wrap_meme.result_for(self,orig_value)
    }
  }
}

}