messed 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. data/Gemfile +8 -0
  2. data/README.rdoc +22 -0
  3. data/Rakefile +76 -0
  4. data/VERSION +1 -0
  5. data/application_spec/Rakefile +12 -0
  6. data/application_spec/app/runner.rb +3 -0
  7. data/application_spec/bin/runner +18 -0
  8. data/application_spec/bin/status +36 -0
  9. data/application_spec/bin/web +29 -0
  10. data/application_spec/config/environment.rb +8 -0
  11. data/application_spec/config/environments/development.rb +0 -0
  12. data/application_spec/log/development.log +6 -0
  13. data/application_spec/spec/application_spec.rb +12 -0
  14. data/application_spec/spec/spec.opts +7 -0
  15. data/application_spec/spec/spec_helper.rb +42 -0
  16. data/bin/messed +9 -0
  17. data/lib/messed/booter.rb +114 -0
  18. data/lib/messed/configuration.rb +94 -0
  19. data/lib/messed/controller/helper.rb +8 -0
  20. data/lib/messed/controller/processing.rb +22 -0
  21. data/lib/messed/controller/respond.rb +48 -0
  22. data/lib/messed/controller.rb +17 -0
  23. data/lib/messed/em_runner.rb +50 -0
  24. data/lib/messed/interface/adapter/sms.rb +4 -0
  25. data/lib/messed/interface/adapter/twitter_consumer.rb +35 -0
  26. data/lib/messed/interface/adapter/twitter_search.rb +111 -0
  27. data/lib/messed/interface/adapter/twitter_sender.rb +44 -0
  28. data/lib/messed/interface/adapter/twitter_streaming.rb +50 -0
  29. data/lib/messed/interface/adapter.rb +68 -0
  30. data/lib/messed/interface/runner.rb +20 -0
  31. data/lib/messed/interface.rb +74 -0
  32. data/lib/messed/logger.rb +50 -0
  33. data/lib/messed/matcher.rb +50 -0
  34. data/lib/messed/message/twitter.rb +23 -0
  35. data/lib/messed/message.rb +35 -0
  36. data/lib/messed/queue/beanstalk.rb +56 -0
  37. data/lib/messed/queue.rb +17 -0
  38. data/lib/messed/session/memcache.rb +40 -0
  39. data/lib/messed/session.rb +7 -0
  40. data/lib/messed/tasks/console.rb +70 -0
  41. data/lib/messed/tasks/generation.rb +12 -0
  42. data/lib/messed/tasks/runner.rb +50 -0
  43. data/lib/messed/tasks/status.rb +37 -0
  44. data/lib/messed/tasks.rb +9 -0
  45. data/lib/messed/util/remote_status.rb +45 -0
  46. data/lib/messed.rb +235 -0
  47. data/patterns/messed/Pattern +24 -0
  48. data/patterns/messed/Rakefile +12 -0
  49. data/patterns/messed/app/runner.rb +5 -0
  50. data/patterns/messed/bin/console +3 -0
  51. data/patterns/messed/bin/runner +3 -0
  52. data/patterns/messed/bin/status +3 -0
  53. data/patterns/messed/bin/web +13 -0
  54. data/patterns/messed/config/environment.rb +15 -0
  55. data/patterns/messed/config/environments/development.rb +2 -0
  56. data/patterns/messed/config/environments/production.rb +0 -0
  57. data/patterns/messed/config/environments/test.rb +0 -0
  58. data/patterns/messed/spec/application_spec.rb +12 -0
  59. data/patterns/messed/spec/spec.opts +7 -0
  60. data/patterns/messed/spec/spec_helper.rb +44 -0
  61. data/spec/adapter/applications/twitter_search/app/application.rb +3 -0
  62. data/spec/adapter/applications/twitter_search/app/runner.rb +7 -0
  63. data/spec/adapter/applications/twitter_search/bin/incoming +89 -0
  64. data/spec/adapter/applications/twitter_search/bin/runner +21 -0
  65. data/spec/adapter/applications/twitter_search/bin/status +36 -0
  66. data/spec/adapter/applications/twitter_search/config/environment.rb +11 -0
  67. data/spec/adapter/applications/twitter_search/config/environments/development.rb +0 -0
  68. data/spec/adapter/applications/twitter_search/log/development.log +1006 -0
  69. data/spec/adapter/applications/twitter_sender/app/application.rb +0 -0
  70. data/spec/adapter/applications/twitter_sender/app/runner.rb +0 -0
  71. data/spec/adapter/applications/twitter_sender/bin/incoming +89 -0
  72. data/spec/adapter/applications/twitter_sender/bin/runner +21 -0
  73. data/spec/adapter/applications/twitter_sender/bin/status +36 -0
  74. data/spec/adapter/applications/twitter_sender/config/environment.rb +11 -0
  75. data/spec/adapter/applications/twitter_sender/config/environments/development.rb +0 -0
  76. data/spec/adapter/applications/twitter_sender/log/development.log +146 -0
  77. data/spec/adapter/http/direct_message +0 -0
  78. data/spec/adapter/http/twitter_search +20 -0
  79. data/spec/adapter/http/update +0 -0
  80. data/spec/adapter/twitter_search_spec.rb +36 -0
  81. data/spec/adapter/twitter_sender_spec.rb +64 -0
  82. data/spec/booter_spec.rb +7 -0
  83. data/spec/fixtures/booter/app/application.rb +3 -0
  84. data/spec/fixtures/booter/app/runner.rb +7 -0
  85. data/spec/fixtures/booter/bin/incoming +89 -0
  86. data/spec/fixtures/booter/bin/runner +21 -0
  87. data/spec/fixtures/booter/bin/status +36 -0
  88. data/spec/fixtures/booter/config/environment.rb +15 -0
  89. data/spec/fixtures/booter/config/environments/development.rb +0 -0
  90. data/spec/fixtures/booter/log/development.log +11 -0
  91. data/spec/message_spec.rb +52 -0
  92. data/spec/session_spec.rb +34 -0
  93. data/spec/spec.opts +7 -0
  94. data/spec/spec_helper.rb +8 -0
  95. data/test/app/runner.rb +5 -0
  96. data/test/config/environment.rb +15 -0
  97. data/test/config/environments/development.rb +2 -0
  98. data/test/config/environments/production.rb +0 -0
  99. data/test/config/environments/test.rb +0 -0
  100. data/test/spec/application_spec.rb +12 -0
  101. data/test/spec/spec_helper.rb +44 -0
  102. metadata +291 -0
@@ -0,0 +1,70 @@
1
+ class Messed
2
+ module Tasks
3
+ class Console
4
+
5
+ module KeyboardHandler
6
+ include EM::Protocols::LineText2
7
+
8
+ attr_accessor :root, :environment
9
+
10
+ def log_outgoing(responses)
11
+ if responses.empty?
12
+ puts "No responses"
13
+ else
14
+ puts "Responding ... #{responses.map{|r| "`#{r.body}'"}.join(', ')}"
15
+ end
16
+ end
17
+
18
+ def prompt
19
+ $stdout << ">> "
20
+ $stdout.flush
21
+ end
22
+
23
+ def post_init
24
+ print_banner
25
+ prompt
26
+ end
27
+
28
+ def print_banner
29
+ puts "? help"
30
+ puts "!q quit"
31
+ puts "Eventhing else is a message"
32
+ end
33
+
34
+ def receive_line(data)
35
+ case data.strip
36
+ when '!q'
37
+ EM.stop_event_loop
38
+ exit
39
+ when '?'
40
+ print_banner
41
+ else
42
+ pid = EM.fork_reactor do
43
+ Booter.new(root, :environment => environment, :supress_banner => true) do |booter|
44
+ Messed::Logger.instance.setup_logger(::Logger.new(STDOUT), :debug)
45
+ log_outgoing(booter.application.process(booter.application.message_class.new(data.strip)))
46
+ EM.stop_event_loop
47
+ end
48
+ end
49
+ Process.wait(pid)
50
+ end
51
+ prompt
52
+ end
53
+ end
54
+
55
+ def self.start
56
+ new.start
57
+ end
58
+
59
+ def start
60
+ EM.run do
61
+ EM.open_keyboard(KeyboardHandler) do |handler|
62
+ handler.root = $root
63
+ handler.environment = ARGV[0]
64
+ end
65
+ end
66
+ end
67
+
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,12 @@
1
+ class Messed
2
+ module Tasks
3
+ class Generation
4
+
5
+ def initialize(name)
6
+ Dressmaker.new(File.join(File.dirname(__FILE__), '..', '..', '..', 'patterns', 'messed'), File.join(Dir.pwd, name)).generate(:app_name => name)
7
+ end
8
+
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,50 @@
1
+ class Messed
2
+ module Tasks
3
+ class Runner < Thor
4
+
5
+ method_options %w( environment -e ) => "development"
6
+ method_options %w( detach -d ) => false
7
+ desc "interface [NAME] [CMD]", "starts an interface (start|stop)"
8
+ def interface(name, cmd)
9
+ case cmd
10
+ when 'start'
11
+ Messed::Booter.new($root, :detach => options.detach?, :environment => options.environment) do |booter|
12
+ interface = booter.interface_for(name.to_sym)
13
+ raise("unable to find an interface with name the `#{name}'") unless interface
14
+ interface.start
15
+ end
16
+ when 'stop'
17
+ Messed::Booter.new($root, :environment => options.environment).interface_for(name.to_sym).stop
18
+ end
19
+ end
20
+
21
+ method_options %w( environment -e ) => "development"
22
+ method_options %w( detach -d ) => false
23
+ desc "application [CMD]", "start the application (start|stop)"
24
+ def application(cmd)
25
+ case cmd
26
+ when 'start'
27
+ Messed::Booter.new($root, :detach => options.detach?, :environment => options.environment) do |booter|
28
+ application = booter.application
29
+ application.start
30
+ end
31
+ when 'stop'
32
+ Messed::Booter.new($root, :environment => options.environment).application.stop
33
+ end
34
+ end
35
+
36
+ method_options %w( environment -e ) => "development"
37
+ method_options %w( detach -d ) => false
38
+ desc "start all interfaces and application [NAME]", "starts all"
39
+ def all
40
+ Messed::Booter.new($root, :detach => options.detach?, :environment => options.environment) do |booter|
41
+ booter.configuration.interfaces.names.each do |name|
42
+ booter.interface_for(name.to_sym).start
43
+ end
44
+ booter.application.start
45
+ end
46
+ end
47
+
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,37 @@
1
+ class Messed
2
+ module Tasks
3
+ class Status < Thor
4
+
5
+ desc "Status", "status"
6
+ method_options :environment => "development"
7
+ def status
8
+ booter = Messed::Booter.new($root, options.environment)
9
+
10
+ puts "=Queues"
11
+ puts "==Incoming"
12
+ booter.application.incoming.status.each {|k,v|
13
+ puts " %40s - %s" % [k, v]
14
+ }
15
+
16
+ puts "==Outgoing"
17
+ booter.application.outgoing.status.each {|k,v|
18
+ puts " %40s - %s" % [k, v]
19
+ }
20
+
21
+ puts "=Interfaces"
22
+ booter.interface_map.each {|name, interface|
23
+ puts "==#{interface.name}"
24
+ Messed::Util::RemoteStatus.new(interface.configuration.options['host'], interface.configuration.options['port']).status.each {|k,v|
25
+ puts " %40s - %s" % [k, v]
26
+ }
27
+ }
28
+
29
+ puts "=Application"
30
+ Messed::Util::RemoteStatus.new(booter.application.configuration['host'], booter.application.configuration['port']).status.each {|k,v|
31
+ puts " %40s - %s" % [k, v]
32
+ }
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,9 @@
1
+ class Messed
2
+ module Tasks
3
+ autoload :Generation, File.join('messed', 'tasks', 'generation')
4
+ autoload :Runner, File.join('messed', 'tasks', 'runner')
5
+ autoload :Status, File.join('messed', 'tasks', 'status')
6
+ autoload :Web, File.join('messed', 'tasks', 'web')
7
+ autoload :Console, File.join('messed', 'tasks', 'console')
8
+ end
9
+ end
@@ -0,0 +1,45 @@
1
+ class Messed
2
+ module Util
3
+ class RemoteStatus
4
+
5
+ attr_reader :status
6
+
7
+ class StatusHandler < EM::Connection
8
+
9
+ attr_accessor :status
10
+
11
+ def post_init
12
+ puts "post..."
13
+ send_data "status\r\n"
14
+ end
15
+
16
+ def receive_data(data)
17
+ JSON.parse(data).each do |key, value|
18
+ self.status[key] = status
19
+ end
20
+ EM.stop_event_loop
21
+ end
22
+ end
23
+
24
+ def initialize(host, port)
25
+ host ||= '127.0.0.1'
26
+ @status = {}
27
+ EM.run do
28
+ EM.add_timer(5) {
29
+ @status['error'] = "timeout on connect"
30
+ EM.stop_event_loop
31
+ }
32
+ begin
33
+ EM.connect(host, port, StatusHandler) do |handler|
34
+ handler.status = @status
35
+ end
36
+ rescue
37
+ @status['error'] = "can't connect"
38
+ EM.stop_event_loop
39
+ end
40
+ end
41
+ end
42
+
43
+ end
44
+ end
45
+ end
data/lib/messed.rb ADDED
@@ -0,0 +1,235 @@
1
+ require 'hashify'
2
+ require 'logger'
3
+ require 'time'
4
+ require 'eventmachine'
5
+ require 'em-http'
6
+ require 'em-beanstalk'
7
+ require 'hwia'
8
+ require 'active_support'
9
+ require 'dressmaker'
10
+
11
+ $LOAD_PATH << File.dirname(__FILE__)
12
+
13
+ class Messed
14
+
15
+ autoload :Booter, File.join('messed', 'booter')
16
+ autoload :Configuration, File.join('messed', 'configuration')
17
+ autoload :Controller, File.join('messed', 'controller')
18
+ autoload :EMRunner, File.join('messed', 'em_runner')
19
+ autoload :Interface, File.join('messed', 'interface')
20
+ autoload :Logger, File.join('messed', 'logger')
21
+ autoload :Matcher, File.join('messed', 'matcher')
22
+ autoload :Message, File.join('messed', 'message')
23
+ autoload :Queue, File.join('messed', 'queue')
24
+ autoload :Session, File.join('messed', 'session')
25
+ autoload :Tasks, File.join('messed', 'tasks')
26
+ autoload :Utils, File.join('messed', 'utils')
27
+
28
+ module Util
29
+ autoload :RemoteStatus, File.join('messed', 'util', 'remote_status')
30
+ end
31
+
32
+ include Logger::LoggingModule
33
+ include Controller::Helper
34
+ include Controller::Processing
35
+ include Controller::Respond
36
+
37
+ after_processing :reset!
38
+
39
+ attr_accessor :controller, :booter, :current_matcher
40
+ attr_reader :outgoing, :incoming, :matchers, :session_store, :type, :interface, :name,
41
+ :messages_received_count, :messages_sent_count, :last_message_received, :last_message_sent
42
+
43
+ def initialize(type = :twitter, &block)
44
+ @type = type
45
+ @matchers = []
46
+ @session_store = Session::Memcache.new
47
+ @messages_sent_count = 0
48
+ @messages_received_count = 0
49
+
50
+ @interface = self
51
+ @name = 'Application'
52
+ match(&block) if block
53
+ end
54
+
55
+ def match(&block)
56
+ instance_eval(&block)
57
+ end
58
+
59
+ def reset!
60
+ matchers.clear
61
+ end
62
+
63
+ def message_class
64
+ Message.class_for_type(type)
65
+ end
66
+
67
+ def incoming=(incoming)
68
+ @incoming = incoming
69
+ incoming.application = self
70
+ end
71
+
72
+ def outgoing=(outgoing)
73
+ @outgoing = outgoing
74
+ outgoing.application = self
75
+ end
76
+
77
+ def with(*args, &block)
78
+ matchers << if args.first.is_a?(Hash)
79
+ Matcher::Conditional.new(nil, args.first)
80
+ else
81
+ Matcher::Conditional.new(*args, &block)
82
+ end
83
+ matchers.last.destination = block
84
+ end
85
+
86
+ def otherwise(options = nil, &block)
87
+ matchers << Matcher::Always.new(&block)
88
+ matchers.last.destination = block
89
+ end
90
+ alias_method :always, :otherwise
91
+
92
+ def status_port
93
+ booter.configuration.application.status_port || 19191
94
+ end
95
+
96
+ def status_host
97
+ booter.configuration.application.status_address || '0.0.0.0'
98
+ end
99
+
100
+ def start(continue_forever = true)
101
+ if EM.reactor_running?
102
+ if booter
103
+ EM.start_server(status_host, status_port, EMRunner::StatusHandler) do |c|
104
+ c.interface = self
105
+ end
106
+ logger.info "Status handler for #{self.class} started on #{status_host}:#{status_port}"
107
+ booter.write_pid_file(booter.configuration.application.pid_file)
108
+ end
109
+
110
+ @connection = EM::Beanstalk.new
111
+ @connection.watch(incoming.tube) do
112
+ @connection.use(outgoing.tube) do
113
+ process_incoming(continue_forever)
114
+ end
115
+ end
116
+ else
117
+ EM.run {
118
+ start(continue_forever)
119
+ }
120
+ end
121
+ end
122
+
123
+ def stop
124
+ Process.kill("INT", booter.read_pid_file(booter.configuration.application.pid_file))
125
+ end
126
+
127
+ def process_incoming(continue_forever)
128
+ @connection.reserve(continue_forever ? nil : 0.5) { |job|
129
+ begin
130
+ message = message_class.from_json(job.body)
131
+ process_responses process(message)
132
+ job.delete do
133
+ process_incoming(continue_forever)
134
+ end
135
+ rescue JSON::ParserError
136
+ # unrecoverable
137
+ logger.error "message #{job.body.inspect} not in JSON format"
138
+ job.delete do
139
+ process_incoming(continue_forever)
140
+ end
141
+ end
142
+ }.on_error { |message|
143
+ EM.stop_event_loop
144
+ }
145
+ end
146
+
147
+ def process(message)
148
+ logger.debug("Processing `#{message.body}'")
149
+ increment_messages_received!
150
+ responses = []
151
+
152
+ self.message = message
153
+
154
+ session_store.with(message.unique_id) do |session|
155
+ self.session = session
156
+
157
+ matchers.find do |matcher|
158
+ if matcher.match?(message)
159
+ self.current_matcher = matcher
160
+ controller = process_destination(matcher.destination)
161
+ responses.concat(controller.responses)
162
+ matcher.stop_processing?
163
+ else
164
+ false
165
+ end
166
+ end
167
+
168
+ controller.reset_processing! if controller.respond_to?(:reset_processing!)
169
+ reset_processing!
170
+ end
171
+ responses
172
+ end
173
+
174
+ def extract_destination(options, block)
175
+ block ||
176
+ {:controller => options.delete(:controller) || raise("you must supply a controller"), :action => options.delete(:action) || raise("you must supply an action")} ||
177
+ raise("you need to either supply options or a block")
178
+ end
179
+ protected :extract_destination
180
+
181
+ def reset!
182
+ self.controller = nil
183
+ self.message = nil
184
+ self.params = nil
185
+ self.session = nil
186
+ end
187
+ protected :reset!
188
+
189
+ def process_destination(destination)
190
+ if destination.respond_to?(:call)
191
+ instance_eval(&destination)
192
+ self
193
+ else
194
+ class_name = destination[:controller].to_s.split('_').map{|w| w.capitalize}.join
195
+ self.controller = Kernel.const_get(class_name.to_sym).new
196
+ self.controller.params = params if controller.respond_to?(:params=)
197
+ self.controller.message = message if controller.respond_to?(:message=)
198
+ self.controller.method(destination[:action].to_sym).call
199
+ self.controller
200
+ end
201
+ end
202
+ protected :process_destination
203
+
204
+ def process_responses(responses)
205
+ if responses && !responses.empty?
206
+ logger.debug("Putting response #{responses.first.body} onto outgoing queue")
207
+ @connection.put(responses.shift.to_json) do
208
+ increment_messages_sent!
209
+ process_responses(responses)
210
+ end
211
+ else
212
+ logger.debug("No response.")
213
+ end
214
+ end
215
+
216
+ def status
217
+ {
218
+ :messages_received_count => messages_received_count,
219
+ :messages_sent_count => messages_sent_count,
220
+ :last_message_received => last_message_received,
221
+ :last_message_sent => last_message_sent
222
+ }
223
+ end
224
+
225
+ def increment_messages_sent!
226
+ @messages_sent_count += 1
227
+ @last_message_sent = Time.new
228
+ end
229
+
230
+ def increment_messages_received!
231
+ @messages_received_count += 1
232
+ @last_message_received = Time.new
233
+ end
234
+
235
+ end
@@ -0,0 +1,24 @@
1
+ desc "make executable"
2
+ directory.matches('/bin') do |dir|
3
+ dir.for('*') { |f|
4
+ f.append! <<-HERE_DOC
5
+ #!/usr/bin/env ruby
6
+
7
+ require 'rubygems'
8
+ if ENV['MESSED_HOME']
9
+ require File.join(ENV['MESSED_HOME'], 'lib', 'messed')
10
+ else
11
+ require 'messed'
12
+ end
13
+
14
+ require 'thor'
15
+ HERE_DOC
16
+
17
+ f.make_executable!
18
+ }
19
+ end
20
+
21
+ desc "set application name to #{options[:app_name]}"
22
+ files.all do |f|
23
+ f.gsub!('__APP_NAME__', options[:app_name].inspect)
24
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec'
2
+ require 'spec/rake/spectask'
3
+ task :spec => 'spec:all'
4
+ namespace(:spec) do
5
+ Spec::Rake::SpecTask.new(:all) do |t|
6
+ t.spec_opts ||= []
7
+ t.spec_opts << "-rubygems"
8
+ t.spec_opts << "--options" << "spec/spec.opts"
9
+ t.spec_files = FileList['spec/**/*_spec.rb']
10
+ end
11
+
12
+ end
@@ -0,0 +1,5 @@
1
+ # define your mappings here
2
+
3
+ #with 'hey you' do
4
+ # say 'hey hey'
5
+ #end
@@ -0,0 +1,3 @@
1
+ $root = File.expand_path(File.join(File.dirname(__FILE__), '..'))
2
+
3
+ Messed::Tasks::Console.start
@@ -0,0 +1,3 @@
1
+ $root = File.expand_path(File.join(File.dirname(__FILE__), '..'))
2
+
3
+ Messed::Tasks::Runner.start
@@ -0,0 +1,3 @@
1
+ $root = File.expand_path(File.join(File.dirname(__FILE__), '..'))
2
+
3
+ Messed::Tasks::Status.start
@@ -0,0 +1,13 @@
1
+ class WebTask < Thor
2
+
3
+ method_options :detach => false
4
+ method_options :environment => "development"
5
+ def start
6
+
7
+
8
+
9
+ end
10
+
11
+ end
12
+
13
+ IncomingRunnerTask.start
@@ -0,0 +1,15 @@
1
+ queues.incoming.host = '127.0.0.1'
2
+ queues.incoming.port = 11300
3
+ queues.incoming.tube = 'incoming-tube'
4
+
5
+ queues.outgoing.host = '127.0.0.1'
6
+ queues.outgoing.port = 11300
7
+ queues.outgoing.tube = 'outgoing-tube'
8
+
9
+ # interfaces.search.adapter = :twitter_search
10
+ # interfaces.search.options[:fetch] = {:query => {'q' => 'love'}, :host => 'search.twitter.com', :path => 'search.json'}
11
+ # interfaces.search.options[:interval] = 30
12
+
13
+ # interfaces.twitter_sender.adapter = :twitter_sender
14
+ # interfaces.twitter_sender.options[:username] = 'username'
15
+ # interfaces.twitter_sender.options[:password] = 'password'
@@ -0,0 +1,2 @@
1
+ self.logger = ::Logger.new(STDOUT)
2
+ self.log_level = :debug
File without changes
File without changes
@@ -0,0 +1,12 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe "test" do
4
+
5
+ include MessedSpecHelper
6
+
7
+ it "should have a test" do
8
+ process('this is my message')
9
+ outgoing_messages.size.should == 1
10
+ outgoing_messages.first.body.should == "well, that was fun"
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+ --colour
2
+ --format
3
+ specdoc
4
+ --loadby
5
+ mtime
6
+ --reverse
7
+ --backtrace
@@ -0,0 +1,44 @@
1
+ require 'rubygems'
2
+ begin
3
+ require 'messed'
4
+ rescue LoadError
5
+ if ENV['MESSED_HOME']
6
+ require File.join(ENV['MESSED_HOME'], 'lib', 'messed')
7
+ else
8
+ raise("no messed!")
9
+ end
10
+ end
11
+
12
+ class MessedSpecHolder
13
+
14
+ attr_accessor :booter, :outgoing_messages
15
+
16
+ def initialize
17
+ @booter = Messed::Booter.new(File.join(File.dirname(__FILE__), '..'))
18
+ end
19
+
20
+ def application
21
+ @booter.application
22
+ end
23
+
24
+ def process(message)
25
+ @outgoing_messages = application.process(application.message_class.new(message))
26
+ end
27
+
28
+ end
29
+
30
+
31
+
32
+ module MessedSpecHelper
33
+
34
+ Holder = MessedSpecHolder.new
35
+
36
+ def process(message)
37
+ Holder.process(message)
38
+ end
39
+
40
+ def outgoing_messages
41
+ Holder.outgoing_messages
42
+ end
43
+
44
+ end
@@ -0,0 +1,3 @@
1
+ with 'hey you' do
2
+ say 'hey hey'
3
+ end
@@ -0,0 +1,7 @@
1
+ with 'hey you' do
2
+ say 'hey hey'
3
+ end
4
+
5
+ otherwise do
6
+ say message
7
+ end