Class: Scheherazade::Story

Inherits:
Hash
  • Object
show all
Extended by:
ClassMethods
Defined in:
lib/scheherazade/story.rb

Defined Under Namespace

Modules: ClassMethods

Constant Summary collapse

TOP =
new(nil)

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from ClassMethods

begin, end, tell, to_character, to_character!, to_model

Constructor Details

#initialize(parent = self.class.current) ⇒ Story

Returns a new instance of Story.



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/scheherazade/story.rb', line 59

def initialize(parent = self.class.current)
  super(){|h, k| parent[k] if parent }
  @parent = parent
  @current = Hash.new do |h, k|
    if (char = to_character!(k))
      h[char]
    else
      parent.current[k] if parent
    end
  end
  @fill_attributes = Hash.new{|h, k| parent.fill_attributes[k] if parent }
  @characters = Hash.new {|h, k| parent.characters[k] if parent }
  @counter = parent ? parent.counter.dup : Hash.new(0)
  @filling = []
  @after_imagine = {}
  @built = []
end

Instance Attribute Details

#charactersObject (readonly)

Returns the value of attribute characters.



3
4
5
# File 'lib/scheherazade/story.rb', line 3

def characters
  @characters
end

#counterObject (readonly)

Returns the value of attribute counter.



3
4
5
# File 'lib/scheherazade/story.rb', line 3

def counter
  @counter
end

#currentObject (readonly)

Returns the value of attribute current.



3
4
5
# File 'lib/scheherazade/story.rb', line 3

def current
  @current
end

#fill_attributesObject (readonly)

Returns the value of attribute fill_attributes.



3
4
5
# File 'lib/scheherazade/story.rb', line 3

def fill_attributes
  @fill_attributes
end

Instance Method Details

#after_imagine(&block) ⇒ Object

Raises:

  • (NotImplementedError)


158
159
160
161
# File 'lib/scheherazade/story.rb', line 158

def after_imagine(&block)
  raise NotImplementedError unless model = to_model(current_fill)
  @after_imagine[model] = block
end

#fill(character_or_model, *with) ⇒ Object



146
147
148
149
150
151
152
153
154
155
156
# File 'lib/scheherazade/story.rb', line 146

def fill(character_or_model, *with)
  char = to_character(character_or_model)
  fill_attributes[char] = with
  @characters[char] = current_fill unless to_model(char)
  begin
    @filling.push(char)
    yield
  ensure
    @filling.pop
  end if block_given?
end

#get(character) ⇒ Object



130
131
132
# File 'lib/scheherazade/story.rb', line 130

def get(character)
  current[character] || imagine(character)
end

#imagine(character_or_model, attributes = nil) ⇒ Object

Creates a character with the given attributes

A character can be designated either by the model (e.g. ‘User`), the corresponding symbol (`:user`) or the symbol for a specialized type of character, defined using fill (e.g. `:admin`).

The attributes can be nil, a list of symbols, a hash or a combination of both These, along with attributes passed to fill for the current stories and the mandatory attributes for the model will be provided.

If some fields generate validation errors, they will be provided also.

For associations, the values can also be a character (Symbol or Model), integers (meaning the default Model * that integer) or arrays of characters.

imagine(:user, :account, :company => :fortune_500_company, :emails => 3)

Similarly:

User.imagine(...)
:user.imagine(...)

This record (and any other imagined through associations) will become the current character in the current story:

story.current[User] # => nil
story.tell do
  :admin.imagine # => A User record
  story.current[:admin] # => same
  story.current[User]   # => same
end
story.current[User] # => nil


112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/scheherazade/story.rb', line 112

def imagine(character_or_model, attributes = nil)
  character = to_character(character_or_model)
  prev, @building = @building, [] # because method might be re-entrant
  CharacterBuilder.new(character).build(attributes) do |ar|
    ar.save!
    # While errors on records associated with :has_many will prevent records
    # from being saved, they won't for :belongs_to, so:
    @building.each do |ar|
      ar.valid? and raise ActiveRecord::RecordInvalid, ar.errors unless ar.persisted?
    end
    Scheherazade.log(:saving, character, ar)
    handle_callbacks(@building)
  end
ensure
  @built.concat(@building)
  @building = prev
end

#with(temp_current) ⇒ Object

Allows one to temporarily override the current characters while the given block executes



137
138
139
140
141
142
143
144
# File 'lib/scheherazade/story.rb', line 137

def with(temp_current)
  keys = temp_current.keys.map{|k| to_character(k)}
  previous_values = current.values_at(*keys)
  current.merge!(Hash[keys.zip(temp_current.values)])
  yield
ensure
  current.merge!(Hash[keys.zip(previous_values)])
end