torquebox-messaging 1.1.1-java → 2.0.0.beta1-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. data/lib/gem_hook.rb +26 -3
  2. data/lib/torquebox-messaging.jar +0 -0
  3. data/lib/torquebox-messaging.rb +2 -32
  4. data/lib/torquebox/messaging.rb +16 -0
  5. data/lib/torquebox/messaging/backgroundable.rb +32 -15
  6. data/lib/torquebox/messaging/backgroundable_processor.rb +32 -0
  7. data/lib/torquebox/messaging/connection.rb +127 -0
  8. data/lib/torquebox/messaging/connection_factory.rb +70 -0
  9. data/lib/torquebox/messaging/const_missing.rb +28 -0
  10. data/lib/torquebox/messaging/core.rb +27 -0
  11. data/lib/torquebox/messaging/destination.rb +68 -111
  12. data/lib/torquebox/messaging/ext/javax_jms_queue_browser.rb +1 -3
  13. data/lib/torquebox/messaging/future_responder.rb +10 -7
  14. data/lib/torquebox/messaging/json_message.rb +50 -0
  15. data/lib/torquebox/messaging/marshal_base64_message.rb +44 -0
  16. data/lib/torquebox/messaging/marshal_message.rb +43 -0
  17. data/lib/torquebox/messaging/message.rb +123 -0
  18. data/lib/torquebox/messaging/message_processor.rb +47 -0
  19. data/lib/torquebox/messaging/processor_wrapper.rb +38 -0
  20. data/lib/torquebox/messaging/queue.rb +61 -0
  21. data/lib/torquebox/messaging/session.rb +168 -0
  22. data/lib/torquebox/messaging/task.rb +7 -6
  23. data/lib/torquebox/messaging/text_message.rb +36 -0
  24. data/lib/torquebox/messaging/topic.rb +54 -0
  25. data/lib/torquebox/messaging/xa_connection.rb +58 -0
  26. data/lib/torquebox/messaging/xa_connection_factory.rb +59 -0
  27. data/lib/torquebox/messaging/xa_session.rb +30 -0
  28. data/licenses/lgpl-2.1.txt +7 -9
  29. data/spec/backgroundable_spec.rb +17 -24
  30. data/spec/destination_spec.rb +31 -318
  31. data/spec/future_responder_spec.rb +1 -1
  32. data/spec/json_message_spec.rb +50 -0
  33. data/spec/message_processor_spec.rb +54 -0
  34. data/spec/message_spec.rb +114 -0
  35. data/spec/task_spec.rb +11 -5
  36. metadata +38 -77
  37. data/lib/acl-spi-3.0.0.CR2.jar +0 -0
  38. data/lib/activation-1.1.jar +0 -0
  39. data/lib/authorization-spi-3.0.0.CR2.jar +0 -0
  40. data/lib/dtdparser-1.21.jar +0 -0
  41. data/lib/hornetq-core-2.1.2.Final.jar +0 -0
  42. data/lib/hornetq-jms-client-2.1.2.Final.jar +0 -0
  43. data/lib/hornetq-logging-2.1.2.Final.jar +0 -0
  44. data/lib/identity-spi-3.0.0.CR2.jar +0 -0
  45. data/lib/jaxb-api-2.1.9.jar +0 -0
  46. data/lib/jboss-common-core-2.2.17.GA.jar +0 -0
  47. data/lib/jboss-jms-api_1.1_spec-1.0.0.Final.jar +0 -0
  48. data/lib/jboss-logging-3.0.0.Beta4.jar +0 -0
  49. data/lib/jboss-reflect-2.2.0.GA.jar +0 -0
  50. data/lib/jbosssx-bare-3.0.0.CR2.jar +0 -0
  51. data/lib/jbossxacml-2.0.5.CR1.jar +0 -0
  52. data/lib/jbossxb-2.0.3.GA.jar +0 -0
  53. data/lib/jnp-client-5.0.5.Final.jar +0 -0
  54. data/lib/jruby-complete-1.6.3.jar +0 -0
  55. data/lib/netty-3.2.1.Final.jar +0 -0
  56. data/lib/picketbox-acl-impl-3.0.0.CR2.jar +0 -0
  57. data/lib/picketbox-bare-3.0.0.CR2.jar +0 -0
  58. data/lib/picketbox-identity-impl-3.0.0.CR2.jar +0 -0
  59. data/lib/picketbox-spi-bare-3.0.0.CR2.jar +0 -0
  60. data/lib/torquebox-base-core.jar +0 -0
  61. data/lib/torquebox-base-metadata.jar +0 -0
  62. data/lib/torquebox-base-spi.jar +0 -0
  63. data/lib/torquebox-mc-support.jar +0 -0
  64. data/lib/torquebox-messaging-core.jar +0 -0
  65. data/lib/torquebox/messaging/client.rb +0 -75
  66. data/lib/torquebox/messaging/ext/javax_jms_session.rb +0 -153
  67. data/lib/xercesImpl-2.9.1.jar +0 -0
  68. data/lib/xml-apis-1.3.04.jar +0 -0
  69. data/spec/client_spec.rb +0 -116
  70. data/spec/dispatcher-queues.yml +0 -4
  71. data/spec/dispatcher_not_running.rb +0 -54
  72. data/spec/ext/java_jmx_session_spec.rb +0 -71
  73. data/spec/queues.yml +0 -6
@@ -5,7 +5,7 @@ include TorqueBox::Messaging
5
5
  describe TorqueBox::Messaging::FutureResponder do
6
6
  def self.it_should_publish(message, priority=nil, &block)
7
7
  it "should publish with #{message.inspect}#{priority ? ' and priority :' + priority.to_s : ''}" do
8
- opts = { :correlation_id => 'ham-biscuit', :ttl => 1234 }
8
+ opts = { :correlation_id => 'ham-biscuit', :ttl => 1234, :encoding => :marshal }
9
9
  opts[:priority] = priority if priority
10
10
  queue = mock('queue')
11
11
  responder = FutureResponder.new(queue, 'ham-biscuit', 1234)
@@ -0,0 +1,50 @@
1
+ require 'torquebox/messaging/message'
2
+ require 'torquebox/messaging/json_message'
3
+
4
+ include TorqueBox::Messaging
5
+
6
+ class MockMessage
7
+ include javax.jms::Message
8
+
9
+ attr_accessor :text
10
+ def get_string_property(_)
11
+ "json"
12
+ end
13
+ end
14
+
15
+ def define_JSON
16
+ klass = Class.new {
17
+ def self.fast_generate(_)
18
+ end
19
+ }
20
+ Object.const_set(:JSON, klass)
21
+ end
22
+
23
+
24
+ describe TorqueBox::Messaging::JSONMessage do
25
+ before(:each) do
26
+ @message = Message.new( MockMessage.new )
27
+ end
28
+
29
+ after(:each) do
30
+ Object.send(:remove_const, :JSON) if defined?(JSON)
31
+ end
32
+
33
+ context "requiring json" do
34
+ it "should raise if json isn't available" do
35
+ @message.should_receive(:require).with('json').and_raise(LoadError.new)
36
+ lambda { @message.encode( 'abc' ) }.should raise_error( RuntimeError )
37
+ end
38
+
39
+ it "should not raise if json is available" do
40
+ @message.should_receive(:require).with('json').and_return { define_JSON }
41
+ lambda { @message.encode( 'abc' ) }.should_not raise_error
42
+ end
43
+
44
+ it "should only require json once" do
45
+ @message.should_receive(:require).once.with('json').and_return { define_JSON }
46
+ @message.encode( 'abc' )
47
+ @message.encode( 'abc' )
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,54 @@
1
+ require 'torquebox/messaging/message_processor'
2
+ require 'torquebox/messaging/message'
3
+ require 'torquebox/messaging/marshal_base64_message'
4
+
5
+ class MyTestMessage
6
+ include javax.jms::TextMessage
7
+ attr_accessor :text
8
+ def initialize
9
+ @properties = {}
10
+ end
11
+ def set_string_property k, v
12
+ @properties[k] = v
13
+ end
14
+ def get_string_property k
15
+ @properties[k]
16
+ end
17
+ end
18
+
19
+ class MyTestSession
20
+ include javax.jms::Session
21
+
22
+ def create_text_message
23
+ MyTestMessage.new
24
+ end
25
+ end
26
+
27
+ class MyTestProcessor < TorqueBox::Messaging::MessageProcessor
28
+ attr_accessor :body
29
+ def on_message(body)
30
+ self.body = body
31
+ end
32
+ end
33
+
34
+ describe TorqueBox::Messaging::MessageProcessor do
35
+
36
+ before :each do
37
+ @processor = MyTestProcessor.new
38
+ @jms_session = MyTestSession.new
39
+ end
40
+
41
+ it "should process text messages" do
42
+ @message = TorqueBox::Messaging::Message.new(@jms_session, "foo", :marshal_base64)
43
+ @processor.process! @message
44
+ @processor.body.should eql("foo")
45
+ end
46
+
47
+ it "should process non-text messages" do
48
+ payload = {:foo => "foo", :sym => :sym, "bar" => :bar}
49
+ @message = TorqueBox::Messaging::Message.new(@jms_session, payload, :marshal_base64)
50
+ @processor.process! @message
51
+ @processor.body.should eql(payload)
52
+ end
53
+
54
+ end
@@ -0,0 +1,114 @@
1
+ require 'torquebox/messaging/message'
2
+
3
+ include TorqueBox::Messaging
4
+
5
+ class DummyMessage < Message
6
+ ENCODING = :dummy
7
+ end
8
+
9
+ Message.register_encoding( DummyMessage )
10
+
11
+ def mock_message
12
+ msg = mock( 'JMSMessage' )
13
+ msg.stub( :get_string_property ).and_return( 'dummy' )
14
+ msg
15
+ end
16
+
17
+ describe TorqueBox::Messaging::Message do
18
+
19
+ describe "message property population" do
20
+
21
+ it "should do nothing if no properties are submitted" do
22
+ jms_message = mock_message
23
+ jms_message.should_not_receive(:setStringProperty)
24
+
25
+ Message.new(jms_message).populate_message_properties nil
26
+ end
27
+
28
+ it "should register properties with String keys" do
29
+ properties = {'abc' => 'def'}
30
+
31
+ jms_message = mock_message
32
+ jms_message.should_receive(:set_string_property).with('abc', 'def')
33
+
34
+ Message.new(jms_message).populate_message_properties properties
35
+ end
36
+
37
+ it "should register properties with Symbol keys" do
38
+ properties = {:abc => :def}
39
+
40
+ jms_message = mock_message
41
+ jms_message.should_receive(:set_string_property).with('abc', 'def')
42
+
43
+ Message.new(jms_message).populate_message_properties properties
44
+ end
45
+
46
+ it "should register true as a boolean" do
47
+ properties = {:abc => true}
48
+
49
+ jms_message = mock_message
50
+ jms_message.should_receive(:set_boolean_property).with('abc', true)
51
+
52
+ Message.new(jms_message).populate_message_properties properties
53
+ end
54
+
55
+ it "should register false as a boolean" do
56
+ properties = {:abc => false}
57
+
58
+ jms_message = mock_message
59
+ jms_message.should_receive(:set_boolean_property).with('abc', false)
60
+
61
+ Message.new(jms_message).populate_message_properties properties
62
+ end
63
+
64
+ it "should register 5 as an long" do
65
+ properties = {:abc => 5}
66
+
67
+ jms_message = mock_message
68
+ jms_message.should_receive(:set_long_property).with('abc', 5)
69
+
70
+ Message.new(jms_message).populate_message_properties properties
71
+ end
72
+
73
+ it "should register 5.5 as a double" do
74
+ properties = {:abc => 5.5}
75
+
76
+ jms_message = mock_message
77
+ jms_message.should_receive(:set_double_property).with('abc', 5.5)
78
+
79
+ Message.new(jms_message).populate_message_properties properties
80
+ end
81
+ end
82
+
83
+ describe 'encodings' do
84
+ before(:each) do
85
+ @class = mock("MessageSubClass", :new => nil)
86
+ @session = mock("Session", :is_a? => true)
87
+ end
88
+
89
+ it 'should use the default encoding if none provided' do
90
+ Message.should_receive(:class_for_encoding).with(Message::DEFAULT_ENCODE_ENCODING).and_return(@class)
91
+ Message.new(@session)
92
+ end
93
+
94
+ it 'should use the given encoding if provided' do
95
+ Message.should_receive(:class_for_encoding).with(:biscuit).and_return(@class)
96
+ Message.new(@session, nil, :biscuit)
97
+ end
98
+
99
+ it 'should use the encoding from the env if set and no encoding is passed to the constructor' do
100
+ ENV['DEFAULT_MESSAGE_ENCODING'] = 'ham'
101
+ Message.should_receive(:class_for_encoding).with(:ham).and_return(@class)
102
+ Message.new(@session)
103
+ ENV['DEFAULT_MESSAGE_ENCODING'] = nil
104
+ end
105
+
106
+ it 'should ignore the encoding from the env if set and an encoding is passed to the constructor' do
107
+ ENV['DEFAULT_MESSAGE_ENCODING'] = 'ham'
108
+ Message.should_receive(:class_for_encoding).with(:biscuit).and_return(@class)
109
+ Message.new(@session, nil, :biscuit)
110
+ ENV['DEFAULT_MESSAGE_ENCODING'] = nil
111
+ end
112
+ end
113
+
114
+ end
data/spec/task_spec.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'torquebox/messaging/future_responder'
2
2
  require 'torquebox/messaging/future'
3
- require 'torquebox/messaging/destination'
3
+ require 'torquebox/messaging/queue'
4
4
  require 'torquebox/messaging/task'
5
5
 
6
6
  class MyTestTask < TorqueBox::Messaging::Task
@@ -29,14 +29,14 @@ describe TorqueBox::Messaging::Task do
29
29
  end
30
30
 
31
31
  it "should send payload correctly" do
32
- expectation = [{:method => :payload=, :payload => {:foo => 'bar'}, :future_id => '1234', :future_queue => MyTestTask.queue_name}, { }]
32
+ expectation = [{:method => :payload=, :payload => {:foo => 'bar'}, :future_id => '1234', :future_queue => MyTestTask.queue_name('my_test')}, anything]
33
33
  @send_queue.should_receive(:publish).with(*expectation)
34
34
 
35
35
  MyTestTask.async(:payload=, :foo => 'bar')
36
36
  end
37
37
 
38
38
  it "should handle nil payload as empty hash" do
39
- @send_queue.should_receive(:publish).with(hash_including(:payload => {}), {})
39
+ @send_queue.should_receive(:publish).with(hash_including(:payload => {}), anything)
40
40
 
41
41
  MyTestTask.async(:payload=)
42
42
  end
@@ -45,11 +45,17 @@ describe TorqueBox::Messaging::Task do
45
45
  result = MyTestTask.async(:payload=)
46
46
  result.is_a?(TorqueBox::Messaging::Future).should be_true
47
47
  end
48
+
49
+ it "should always use the :marshal encoding" do
50
+ @send_queue.should_receive(:publish).with(anything, hash_including(:encoding => :marshal))
51
+
52
+ MyTestTask.async(:payload=)
53
+ end
48
54
  end
49
55
 
50
56
  describe "#process!" do
51
57
  it "should process payload correctly" do
52
- expectation = {:method => :payload=, :payload => {:foo => 'bar'}, :future_id => '1234', :future_queue => MyTestTask.queue_name}
58
+ expectation = {:method => :payload=, :payload => {:foo => 'bar'}, :future_id => '1234', :future_queue => MyTestTask.queue_name('my_test')}
53
59
  message = mock("message")
54
60
  message.should_receive(:decode).and_return(expectation)
55
61
 
@@ -58,7 +64,7 @@ describe TorqueBox::Messaging::Task do
58
64
  task.payload[:foo].should == 'bar'
59
65
  end
60
66
  end
61
-
67
+
62
68
  describe 'the future proxy' do
63
69
  it "should be available inside a task method" do
64
70
  TorqueBox::Messaging::FutureResponder.should_receive(:status=).with(1)
metadata CHANGED
@@ -1,8 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: torquebox-messaging
3
3
  version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 1.1.1
4
+ prerelease: 6
5
+ version: 2.0.0.beta1
6
6
  platform: java
7
7
  authors:
8
8
  - The TorqueBox Team
@@ -10,64 +10,41 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-08-09 00:00:00 -04:00
14
- default_executable:
13
+ date: 2011-12-02 00:00:00 Z
15
14
  dependencies:
16
15
  - !ruby/object:Gem::Dependency
17
- name: torquebox-naming
16
+ name: torquebox-core
18
17
  prerelease: false
19
18
  requirement: &id001 !ruby/object:Gem::Requirement
20
19
  none: false
21
20
  requirements:
22
21
  - - "="
23
22
  - !ruby/object:Gem::Version
24
- version: 1.1.1
23
+ version: 2.0.0.beta1
25
24
  type: :runtime
26
25
  version_requirements: *id001
27
26
  - !ruby/object:Gem::Dependency
28
- name: torquebox-naming-container
27
+ name: torquebox-transactions
29
28
  prerelease: false
30
29
  requirement: &id002 !ruby/object:Gem::Requirement
31
30
  none: false
32
31
  requirements:
33
32
  - - "="
34
33
  - !ruby/object:Gem::Version
35
- version: 1.1.1
36
- type: :development
34
+ version: 2.0.0.beta1
35
+ type: :runtime
37
36
  version_requirements: *id002
38
37
  - !ruby/object:Gem::Dependency
39
- name: torquebox-messaging-container
38
+ name: rspec
40
39
  prerelease: false
41
40
  requirement: &id003 !ruby/object:Gem::Requirement
42
41
  none: false
43
42
  requirements:
44
43
  - - "="
45
44
  - !ruby/object:Gem::Version
46
- version: 1.1.1
45
+ version: 2.7.0
47
46
  type: :development
48
47
  version_requirements: *id003
49
- - !ruby/object:Gem::Dependency
50
- name: torquebox-base
51
- prerelease: false
52
- requirement: &id004 !ruby/object:Gem::Requirement
53
- none: false
54
- requirements:
55
- - - "="
56
- - !ruby/object:Gem::Version
57
- version: 1.1.1
58
- type: :runtime
59
- version_requirements: *id004
60
- - !ruby/object:Gem::Dependency
61
- name: rspec
62
- prerelease: false
63
- requirement: &id005 !ruby/object:Gem::Requirement
64
- none: false
65
- requirements:
66
- - - "="
67
- - !ruby/object:Gem::Version
68
- version: 2.3.0
69
- type: :development
70
- version_requirements: *id005
71
48
  description: ""
72
49
  email:
73
50
  - torquebox-dev@torquebox.org
@@ -81,60 +58,43 @@ files:
81
58
  - licenses/lgpl-2.1.txt
82
59
  - lib/torquebox-messaging.jar
83
60
  - lib/torquebox-messaging.rb
84
- - lib/jboss-jms-api_1.1_spec-1.0.0.Final.jar
85
- - lib/hornetq-core-2.1.2.Final.jar
86
- - lib/hornetq-jms-client-2.1.2.Final.jar
87
- - lib/netty-3.2.1.Final.jar
88
- - lib/hornetq-logging-2.1.2.Final.jar
89
- - lib/jboss-logging-3.0.0.Beta4.jar
90
- - lib/jnp-client-5.0.5.Final.jar
91
- - lib/jboss-common-core-2.2.17.GA.jar
92
- - lib/jboss-reflect-2.2.0.GA.jar
93
- - lib/jbossxb-2.0.3.GA.jar
94
- - lib/xml-apis-1.3.04.jar
95
- - lib/xercesImpl-2.9.1.jar
96
- - lib/dtdparser-1.21.jar
97
- - lib/activation-1.1.jar
98
- - lib/jaxb-api-2.1.9.jar
99
- - lib/torquebox-base-spi.jar
100
- - lib/jruby-complete-1.6.3.jar
101
- - lib/torquebox-base-metadata.jar
102
- - lib/torquebox-base-core.jar
103
- - lib/picketbox-bare-3.0.0.CR2.jar
104
- - lib/identity-spi-3.0.0.CR2.jar
105
- - lib/authorization-spi-3.0.0.CR2.jar
106
- - lib/acl-spi-3.0.0.CR2.jar
107
- - lib/jbosssx-bare-3.0.0.CR2.jar
108
- - lib/picketbox-identity-impl-3.0.0.CR2.jar
109
- - lib/picketbox-spi-bare-3.0.0.CR2.jar
110
- - lib/picketbox-acl-impl-3.0.0.CR2.jar
111
- - lib/jbossxacml-2.0.5.CR1.jar
112
- - lib/torquebox-mc-support.jar
113
- - lib/torquebox-messaging-core.jar
114
61
  - lib/gem_hook.rb
115
62
  - lib/org.torquebox.messaging-client.rb
116
63
  - lib/torquebox/messaging.rb
117
64
  - lib/torquebox/messaging/backgroundable.rb
118
- - lib/torquebox/messaging/client.rb
65
+ - lib/torquebox/messaging/backgroundable_processor.rb
66
+ - lib/torquebox/messaging/connection.rb
67
+ - lib/torquebox/messaging/connection_factory.rb
68
+ - lib/torquebox/messaging/const_missing.rb
69
+ - lib/torquebox/messaging/core.rb
119
70
  - lib/torquebox/messaging/destination.rb
120
71
  - lib/torquebox/messaging/future.rb
121
72
  - lib/torquebox/messaging/future_responder.rb
122
73
  - lib/torquebox/messaging/future_status.rb
74
+ - lib/torquebox/messaging/json_message.rb
75
+ - lib/torquebox/messaging/marshal_base64_message.rb
76
+ - lib/torquebox/messaging/marshal_message.rb
77
+ - lib/torquebox/messaging/message.rb
78
+ - lib/torquebox/messaging/message_processor.rb
79
+ - lib/torquebox/messaging/processor_wrapper.rb
80
+ - lib/torquebox/messaging/queue.rb
81
+ - lib/torquebox/messaging/session.rb
123
82
  - lib/torquebox/messaging/task.rb
83
+ - lib/torquebox/messaging/text_message.rb
84
+ - lib/torquebox/messaging/topic.rb
85
+ - lib/torquebox/messaging/xa_connection.rb
86
+ - lib/torquebox/messaging/xa_connection_factory.rb
87
+ - lib/torquebox/messaging/xa_session.rb
124
88
  - lib/torquebox/messaging/ext/javax_jms_queue_browser.rb
125
- - lib/torquebox/messaging/ext/javax_jms_session.rb
126
89
  - spec/backgroundable_spec.rb
127
- - spec/client_spec.rb
128
90
  - spec/destination_spec.rb
129
- - spec/dispatcher-queues.yml
130
- - spec/dispatcher_not_running.rb
131
91
  - spec/future_responder_spec.rb
132
92
  - spec/future_spec.rb
133
- - spec/queues.yml
93
+ - spec/json_message_spec.rb
94
+ - spec/message_processor_spec.rb
95
+ - spec/message_spec.rb
134
96
  - spec/task_spec.rb
135
- - spec/ext/java_jmx_session_spec.rb
136
- has_rdoc: true
137
- homepage: http://www.torquebox.org/client-parent/torquebox-messaging/
97
+ homepage: http://www.torquebox.org/torquebox-gems-parent/torquebox-messaging/
138
98
  licenses:
139
99
  - lgpl
140
100
  post_install_message:
@@ -151,21 +111,22 @@ required_ruby_version: !ruby/object:Gem::Requirement
151
111
  required_rubygems_version: !ruby/object:Gem::Requirement
152
112
  none: false
153
113
  requirements:
154
- - - ">="
114
+ - - ">"
155
115
  - !ruby/object:Gem::Version
156
- version: "0"
116
+ version: 1.3.1
157
117
  requirements: []
158
118
 
159
119
  rubyforge_project:
160
- rubygems_version: 1.5.1
120
+ rubygems_version: 1.8.9
161
121
  signing_key:
162
122
  specification_version: 3
163
123
  summary: TorqueBox Messaging Client
164
124
  test_files:
165
125
  - spec/backgroundable_spec.rb
166
- - spec/client_spec.rb
167
126
  - spec/destination_spec.rb
168
127
  - spec/future_responder_spec.rb
169
128
  - spec/future_spec.rb
129
+ - spec/json_message_spec.rb
130
+ - spec/message_processor_spec.rb
131
+ - spec/message_spec.rb
170
132
  - spec/task_spec.rb
171
- - spec/ext/java_jmx_session_spec.rb