Class: Markdoc::Sequence::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/markdoc/sequence.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(source, options = {}) ⇒ Parser

Returns a new instance of Parser.



89
90
91
92
93
94
95
96
97
98
# File 'lib/markdoc/sequence.rb', line 89

def initialize(source, options = {})
  self.source = source
  self.output = []
  self.roles = []
  self.messages = []
  self.variables = defaults.dup
  options.each do |key, value|
    variables[key] = value
  end
end

Instance Attribute Details

#messagesObject

Returns the value of attribute messages.



73
74
75
# File 'lib/markdoc/sequence.rb', line 73

def messages
  @messages
end

#outputObject

Returns the value of attribute output.



73
74
75
# File 'lib/markdoc/sequence.rb', line 73

def output
  @output
end

#rolesObject

Returns the value of attribute roles.



73
74
75
# File 'lib/markdoc/sequence.rb', line 73

def roles
  @roles
end

#sourceObject

Returns the value of attribute source.



73
74
75
# File 'lib/markdoc/sequence.rb', line 73

def source
  @source
end

#variablesObject

Returns the value of attribute variables.



73
74
75
# File 'lib/markdoc/sequence.rb', line 73

def variables
  @variables
end

Instance Method Details

#defaultsObject



75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/markdoc/sequence.rb', line 75

def defaults
  {
    boxht:     '0.5', # Object box height
    boxwid:    '1.3', # Object box width
    awid:      '0.1', # Active lifeline width
    spacing:   '0.25', # Spacing between messages
    movewid:   '0.75', # Spacing between objects
    dashwid:   '0.05', # Interval for dashed lines
    maxpswid:  '20', # Maximum width of picture
    maxpsht:   '20', # Maximum height of picture
    underline: '0', # Underline the name of objects
  }
end

#find(id) ⇒ Object



100
101
102
103
# File 'lib/markdoc/sequence.rb', line 100

def find(id)
  id.strip!
  roles.detect{|role| role.id == id}
end


199
200
201
202
203
204
205
206
207
208
# File 'lib/markdoc/sequence.rb', line 199

def footer
  output << ''
  output << 'step();'
  output << '# Complete the lifelines'
  roles.each do |object|
    output << "complete(#{object.id});"
  end
  output << ''
  output << '.PE'
end

#headerObject



174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/markdoc/sequence.rb', line 174

def header
  headers = []
  headers << '.PS'
  headers << ''
  headers << macros
  headers << ''
  headers << '# Variables'
  # calculate height

  variables[:maxpsht] = ((variables[:spacing].to_f *
                          messages.map(&:height).reduce(:+)) +
                         variables[:boxht].to_f).ceil

  variables.each do |key, value|
    headers << "#{key} = #{value};"
  end
  headers << '# Actors and Objects'
  roles.each do |object|
    headers << %Q[#{object.type}(#{object.id},"#{object.label}");]
  end
  headers << 'step();'
  headers << ''
  self.output =  headers + output
end

#macrosObject



170
171
172
# File 'lib/markdoc/sequence.rb', line 170

def macros
  IO.read File.join(File.dirname(__FILE__), 'sequence.pic')
end

#parseObject



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/markdoc/sequence.rb', line 105

def parse
  source.split("\n").each do |line|
    next if line.strip.empty?
    if match = line.match(/^([a-zA-Z0-9_ \t]+) *= *([a-zA-Z0-9_ \t]+)/)
      if match[2] =~ /Actor/
        roles << Role.new(:actor, match[1].strip, match[1].strip)
      else
        roles << Role.new(:object, match[1].strip, match[2].strip)
      end
    elsif match = line.match(/^([a-zA-Z0-9_ \t]+) *([<\-~>]{2}) *([a-zA-Z0-9_ \t]+):([^#]+)#?(.*)/)
      role1, role2, op = find(match[1]), find(match[3]), match[2]

      if op.index('>')
        source, dest = role1, role2
      elsif op.index('<')
        source, dest = role2, role1
      else
        raise "Message direction must be one of ->, ~>, <-, <~"
      end

      if op.index('-')
        type = :message
      elsif op.index('~')
        type = :rmessage
      else
        raise "Message direction must be one of ->, ~>, <-, <~"
      end

      message = Message.new(type, source, dest, match[4], match[5])
      # deactivate prev messages roles
      if last = messages.last
        (last.roles - message.roles).each do |role|
          output << role.deactivate if role.active
        end
      end
      # activate source before send message
      output << source.activate unless source.active
      output << message.deliver
      output << message.describe
      # activate dest
      output << dest.activate unless dest.active
      messages << message
    elsif match = line.match(/^([a-zA-Z0-9_ \t]+) *:([^#]+)#?(.*)/)
      role = find(match[1])
      message = Message.new(:message, role, role, match[2], match[3])
      # deactivate prev messages roles
      if last = messages.last
        (last.roles - message.roles).each do |role|
          output << role.deactivate if role.active
        end
      end
      # activate role before send message
      output << role.activate unless role.active
      output << message.deliver
      output << message.describe
      messages << message
    end
  end

  header
  footer

  output.compact.join("\n")
end