cadence-ruby 0.0.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +456 -0
  3. data/cadence.gemspec +9 -2
  4. data/lib/cadence-ruby.rb +1 -0
  5. data/lib/cadence.rb +176 -0
  6. data/lib/cadence/activity.rb +33 -0
  7. data/lib/cadence/activity/async_token.rb +34 -0
  8. data/lib/cadence/activity/context.rb +64 -0
  9. data/lib/cadence/activity/poller.rb +89 -0
  10. data/lib/cadence/activity/task_processor.rb +73 -0
  11. data/lib/cadence/activity/workflow_convenience_methods.rb +41 -0
  12. data/lib/cadence/client.rb +21 -0
  13. data/lib/cadence/client/errors.rb +8 -0
  14. data/lib/cadence/client/thrift_client.rb +380 -0
  15. data/lib/cadence/concerns/executable.rb +33 -0
  16. data/lib/cadence/concerns/typed.rb +40 -0
  17. data/lib/cadence/configuration.rb +36 -0
  18. data/lib/cadence/errors.rb +21 -0
  19. data/lib/cadence/executable_lookup.rb +25 -0
  20. data/lib/cadence/execution_options.rb +32 -0
  21. data/lib/cadence/json.rb +18 -0
  22. data/lib/cadence/metadata.rb +73 -0
  23. data/lib/cadence/metadata/activity.rb +28 -0
  24. data/lib/cadence/metadata/base.rb +17 -0
  25. data/lib/cadence/metadata/decision.rb +25 -0
  26. data/lib/cadence/metadata/workflow.rb +23 -0
  27. data/lib/cadence/metrics.rb +37 -0
  28. data/lib/cadence/metrics_adapters/log.rb +33 -0
  29. data/lib/cadence/metrics_adapters/null.rb +9 -0
  30. data/lib/cadence/middleware/chain.rb +30 -0
  31. data/lib/cadence/middleware/entry.rb +9 -0
  32. data/lib/cadence/retry_policy.rb +27 -0
  33. data/lib/cadence/saga/concern.rb +37 -0
  34. data/lib/cadence/saga/result.rb +22 -0
  35. data/lib/cadence/saga/saga.rb +24 -0
  36. data/lib/cadence/testing.rb +50 -0
  37. data/lib/cadence/testing/cadence_override.rb +112 -0
  38. data/lib/cadence/testing/future_registry.rb +27 -0
  39. data/lib/cadence/testing/local_activity_context.rb +17 -0
  40. data/lib/cadence/testing/local_workflow_context.rb +207 -0
  41. data/lib/cadence/testing/workflow_execution.rb +44 -0
  42. data/lib/cadence/testing/workflow_override.rb +36 -0
  43. data/lib/cadence/thread_local_context.rb +14 -0
  44. data/lib/cadence/thread_pool.rb +68 -0
  45. data/lib/cadence/types.rb +7 -0
  46. data/lib/cadence/utils.rb +17 -0
  47. data/lib/cadence/uuid.rb +19 -0
  48. data/lib/cadence/version.rb +1 -1
  49. data/lib/cadence/worker.rb +91 -0
  50. data/lib/cadence/workflow.rb +42 -0
  51. data/lib/cadence/workflow/context.rb +266 -0
  52. data/lib/cadence/workflow/convenience_methods.rb +34 -0
  53. data/lib/cadence/workflow/decision.rb +39 -0
  54. data/lib/cadence/workflow/decision_state_machine.rb +48 -0
  55. data/lib/cadence/workflow/decision_task_processor.rb +105 -0
  56. data/lib/cadence/workflow/dispatcher.rb +31 -0
  57. data/lib/cadence/workflow/execution_info.rb +45 -0
  58. data/lib/cadence/workflow/executor.rb +45 -0
  59. data/lib/cadence/workflow/future.rb +75 -0
  60. data/lib/cadence/workflow/history.rb +76 -0
  61. data/lib/cadence/workflow/history/event.rb +71 -0
  62. data/lib/cadence/workflow/history/event_target.rb +79 -0
  63. data/lib/cadence/workflow/history/window.rb +40 -0
  64. data/lib/cadence/workflow/poller.rb +74 -0
  65. data/lib/cadence/workflow/replay_aware_logger.rb +36 -0
  66. data/lib/cadence/workflow/serializer.rb +31 -0
  67. data/lib/cadence/workflow/serializer/base.rb +22 -0
  68. data/lib/cadence/workflow/serializer/cancel_timer.rb +19 -0
  69. data/lib/cadence/workflow/serializer/complete_workflow.rb +20 -0
  70. data/lib/cadence/workflow/serializer/fail_workflow.rb +21 -0
  71. data/lib/cadence/workflow/serializer/record_marker.rb +21 -0
  72. data/lib/cadence/workflow/serializer/request_activity_cancellation.rb +19 -0
  73. data/lib/cadence/workflow/serializer/schedule_activity.rb +54 -0
  74. data/lib/cadence/workflow/serializer/start_child_workflow.rb +52 -0
  75. data/lib/cadence/workflow/serializer/start_timer.rb +20 -0
  76. data/lib/cadence/workflow/state_manager.rb +324 -0
  77. data/lib/gen/thrift/cadence_constants.rb +11 -0
  78. data/lib/gen/thrift/cadence_types.rb +11 -0
  79. data/lib/gen/thrift/shared_constants.rb +11 -0
  80. data/lib/gen/thrift/shared_types.rb +4600 -0
  81. data/lib/gen/thrift/workflow_service.rb +3142 -0
  82. data/rbi/cadence-ruby.rbi +39 -0
  83. metadata +152 -5
@@ -0,0 +1,44 @@
1
+ require 'cadence/testing/future_registry'
2
+
3
+ module Cadence
4
+ module Testing
5
+ class WorkflowExecution
6
+ attr_reader :status
7
+
8
+ def initialize
9
+ @status = Workflow::ExecutionInfo::RUNNING_STATUS
10
+ @futures = FutureRegistry.new
11
+ end
12
+
13
+ def run(&block)
14
+ @fiber = Fiber.new(&block)
15
+ resume
16
+ end
17
+
18
+ def resume
19
+ fiber.resume
20
+ @status = Workflow::ExecutionInfo::COMPLETED_STATUS unless fiber.alive?
21
+ rescue StandardError
22
+ @status = Workflow::ExecutionInfo::FAILED_STATUS
23
+ end
24
+
25
+ def register_future(token, future)
26
+ futures.register(token, future)
27
+ end
28
+
29
+ def complete_activity(token, result)
30
+ futures.complete(token, result)
31
+ resume
32
+ end
33
+
34
+ def fail_activity(token, error)
35
+ futures.fail(token, error)
36
+ resume
37
+ end
38
+
39
+ private
40
+
41
+ attr_reader :fiber, :futures
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,36 @@
1
+ require 'securerandom'
2
+ require 'cadence/testing/local_workflow_context'
3
+ require 'cadence/testing/workflow_execution'
4
+
5
+ module Cadence
6
+ module Testing
7
+ module WorkflowOverride
8
+ def disabled_releases
9
+ @disabled_releases ||= Set.new
10
+ end
11
+
12
+ def allow_all_releases
13
+ disabled_releases.clear
14
+ end
15
+
16
+ def allow_release(release_name)
17
+ disabled_releases.delete(release_name.to_s)
18
+ end
19
+
20
+ def disable_release(release_name)
21
+ disabled_releases << release_name.to_s
22
+ end
23
+
24
+ def execute_locally(*input)
25
+ workflow_id = SecureRandom.uuid
26
+ run_id = SecureRandom.uuid
27
+ execution = WorkflowExecution.new
28
+ context = Cadence::Testing::LocalWorkflowContext.new(
29
+ execution, workflow_id, run_id, disabled_releases
30
+ )
31
+
32
+ execute_in_context(context, input)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,14 @@
1
+ # Provides context for Cadence::Activity::WorkflowConvenienceMethods
2
+ module Cadence
3
+ module ThreadLocalContext
4
+ WORKFLOW_CONTEXT_KEY = :cadence_workflow_context
5
+
6
+ def self.get
7
+ Thread.current[WORKFLOW_CONTEXT_KEY]
8
+ end
9
+
10
+ def self.set(context)
11
+ Thread.current[WORKFLOW_CONTEXT_KEY] = context
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,68 @@
1
+ # This class implements a very simple ThreadPool with the ability to
2
+ # block until at least one thread becomes available. This allows Pollers
3
+ # to only poll when there's an available thread in the pool.
4
+ #
5
+ # NOTE: There's a minor race condition that can occur between calling
6
+ # #wait_for_available_threads and #schedule, but should be rare
7
+ #
8
+ module Cadence
9
+ class ThreadPool
10
+ attr_reader :size
11
+
12
+ def initialize(size)
13
+ @size = size
14
+ @queue = Queue.new
15
+ @mutex = Mutex.new
16
+ @availability = ConditionVariable.new
17
+ @available_threads = size
18
+ @pool = Array.new(size) do |i|
19
+ Thread.new { poll }
20
+ end
21
+ end
22
+
23
+ def wait_for_available_threads
24
+ @mutex.synchronize do
25
+ while @available_threads <= 0
26
+ @availability.wait(@mutex)
27
+ end
28
+ end
29
+ end
30
+
31
+ def schedule(&block)
32
+ @mutex.synchronize do
33
+ @available_threads -= 1
34
+ @queue << block
35
+ end
36
+ end
37
+
38
+ def shutdown
39
+ size.times do
40
+ schedule { throw EXIT_SYMBOL }
41
+ end
42
+
43
+ @pool.each(&:join)
44
+ end
45
+
46
+ private
47
+
48
+ EXIT_SYMBOL = :exit
49
+
50
+ def poll
51
+ catch(EXIT_SYMBOL) do
52
+ loop do
53
+ run(@queue.pop)
54
+ @mutex.synchronize do
55
+ @available_threads += 1
56
+ @availability.signal
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ def run(job)
63
+ job.call if job
64
+ rescue Exception
65
+ # Make sure we don't loose a thread
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,7 @@
1
+ require 'dry-types'
2
+
3
+ module Cadence
4
+ module Types
5
+ include Dry.Types
6
+ end
7
+ end
@@ -0,0 +1,17 @@
1
+ module Cadence
2
+ module Utils
3
+ NANO = 10**9
4
+ MILLI = 10**3
5
+
6
+ class << self
7
+ def time_from_nanos(timestamp)
8
+ seconds, nanoseconds = timestamp.divmod(NANO)
9
+ Time.at(seconds, nanoseconds, :nsec)
10
+ end
11
+
12
+ def time_to_nanos(time)
13
+ time.to_f * NANO
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+ # This is a simple UUIDv5 (SHA1) implementation adopted from:
2
+ # https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/digest/uuid.rb#L18
3
+ require 'digest'
4
+
5
+ module Cadence
6
+ module UUID
7
+ def self.v5(uuid_namespace, name)
8
+ hash = Digest::SHA1.new
9
+ hash.update(uuid_namespace)
10
+ hash.update(name)
11
+
12
+ ary = hash.digest.unpack("NnnnnN")
13
+ ary[2] = (ary[2] & 0x0FFF) | (5 << 12)
14
+ ary[3] = (ary[3] & 0x3FFF) | 0x8000
15
+
16
+ "%08x-%04x-%04x-%04x-%04x%08x" % ary
17
+ end
18
+ end
19
+ end
@@ -1,3 +1,3 @@
1
1
  module Cadence
2
- VERSION = '0.0.0'.freeze
2
+ VERSION = '0.1.0'.freeze
3
3
  end
@@ -0,0 +1,91 @@
1
+ require 'cadence/client'
2
+ require 'cadence/workflow/poller'
3
+ require 'cadence/activity/poller'
4
+ require 'cadence/execution_options'
5
+ require 'cadence/executable_lookup'
6
+ require 'cadence/middleware/entry'
7
+
8
+ module Cadence
9
+ class Worker
10
+ def initialize(options = {})
11
+ @options = options
12
+ @workflows = Hash.new { |hash, key| hash[key] = ExecutableLookup.new }
13
+ @activities = Hash.new { |hash, key| hash[key] = ExecutableLookup.new }
14
+ @pollers = []
15
+ @decision_middleware = []
16
+ @activity_middleware = []
17
+ @shutting_down = false
18
+ end
19
+
20
+ def register_workflow(workflow_class, options = {})
21
+ execution_options = ExecutionOptions.new(workflow_class, options)
22
+ key = [execution_options.domain, execution_options.task_list]
23
+
24
+ @workflows[key].add(execution_options.name, workflow_class)
25
+ end
26
+
27
+ def register_activity(activity_class, options = {})
28
+ execution_options = ExecutionOptions.new(activity_class, options)
29
+ key = [execution_options.domain, execution_options.task_list]
30
+
31
+ @activities[key].add(execution_options.name, activity_class)
32
+ end
33
+
34
+ def add_decision_middleware(middleware_class, *args)
35
+ @decision_middleware << Middleware::Entry.new(middleware_class, args)
36
+ end
37
+
38
+ def add_activity_middleware(middleware_class, *args)
39
+ @activity_middleware << Middleware::Entry.new(middleware_class, args)
40
+ end
41
+
42
+ def start
43
+ workflows.each_pair do |(domain, task_list), lookup|
44
+ pollers << workflow_poller_for(domain, task_list, lookup)
45
+ end
46
+
47
+ activities.each_pair do |(domain, task_list), lookup|
48
+ pollers << activity_poller_for(domain, task_list, lookup)
49
+ end
50
+
51
+ trap_signals
52
+
53
+ pollers.each(&:start)
54
+
55
+ # keep the main worker thread alive
56
+ sleep(1) while !shutting_down?
57
+ end
58
+
59
+ def stop
60
+ @shutting_down = true
61
+
62
+ Thread.new do
63
+ pollers.each(&:stop)
64
+ pollers.each(&:wait)
65
+ end.join
66
+ end
67
+
68
+ private
69
+
70
+ attr_reader :options, :activities, :workflows, :pollers,
71
+ :decision_middleware, :activity_middleware
72
+
73
+ def shutting_down?
74
+ @shutting_down
75
+ end
76
+
77
+ def workflow_poller_for(domain, task_list, lookup)
78
+ Workflow::Poller.new(domain, task_list, lookup.freeze, decision_middleware, options)
79
+ end
80
+
81
+ def activity_poller_for(domain, task_list, lookup)
82
+ Activity::Poller.new(domain, task_list, lookup.freeze, activity_middleware, options)
83
+ end
84
+
85
+ def trap_signals
86
+ %w[TERM INT].each do |signal|
87
+ Signal.trap(signal) { stop }
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,42 @@
1
+ require 'cadence/concerns/executable'
2
+ require 'cadence/workflow/convenience_methods'
3
+ require 'cadence/thread_local_context'
4
+
5
+ module Cadence
6
+ class Workflow
7
+ extend Concerns::Executable
8
+ extend ConvenienceMethods
9
+
10
+ def self.execute_in_context(context, input)
11
+ Cadence::ThreadLocalContext.set(context)
12
+
13
+ workflow = new(context)
14
+ result = workflow.execute(*input)
15
+
16
+ context.complete(result)
17
+ rescue StandardError, ScriptError => error
18
+ Cadence.logger.error("Workflow execution failed with: #{error.inspect}")
19
+ Cadence.logger.debug(error.backtrace.join("\n"))
20
+
21
+ context.fail(error.class.name, error.message)
22
+ end
23
+
24
+ def initialize(context)
25
+ @context = context
26
+ end
27
+
28
+ def execute
29
+ raise NotImplementedError, '#execute method must be implemented by a subclass'
30
+ end
31
+
32
+ private
33
+
34
+ def workflow
35
+ @context
36
+ end
37
+
38
+ def logger
39
+ workflow.logger
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,266 @@
1
+ require 'securerandom'
2
+
3
+ require 'cadence/execution_options'
4
+ require 'cadence/errors'
5
+ require 'cadence/thread_local_context'
6
+ require 'cadence/workflow/history/event_target'
7
+ require 'cadence/workflow/decision'
8
+ require 'cadence/workflow/future'
9
+ require 'cadence/workflow/replay_aware_logger'
10
+ require 'cadence/workflow/state_manager'
11
+
12
+ # This context class is available in the workflow implementation
13
+ # and provides context and methods for interacting with Cadence
14
+ #
15
+ module Cadence
16
+ class Workflow
17
+ class Context
18
+ def initialize(state_manager, dispatcher, metadata)
19
+ @state_manager = state_manager
20
+ @dispatcher = dispatcher
21
+ @metadata = metadata
22
+ end
23
+
24
+ def logger
25
+ @logger ||= ReplayAwareLogger.new(Cadence.logger)
26
+ @logger.replay = state_manager.replay?
27
+ @logger
28
+ end
29
+
30
+ def headers
31
+ metadata.headers
32
+ end
33
+
34
+ def has_release?(release_name)
35
+ state_manager.release?(release_name.to_s)
36
+ end
37
+
38
+ def execute_activity(activity_class, *input, **args)
39
+ options = args.delete(:options) || {}
40
+ input << args unless args.empty?
41
+
42
+ execution_options = ExecutionOptions.new(activity_class, options)
43
+
44
+ decision = Decision::ScheduleActivity.new(
45
+ activity_id: options[:activity_id],
46
+ activity_type: execution_options.name,
47
+ input: input,
48
+ domain: execution_options.domain,
49
+ task_list: execution_options.task_list,
50
+ retry_policy: execution_options.retry_policy,
51
+ timeouts: execution_options.timeouts,
52
+ headers: execution_options.headers
53
+ )
54
+
55
+ target, cancelation_id = schedule_decision(decision)
56
+ future = Future.new(target, self, cancelation_id: cancelation_id)
57
+
58
+ dispatcher.register_handler(target, 'completed') do |result|
59
+ future.set(result)
60
+ future.callbacks.each { |callback| call_in_fiber(callback, result) }
61
+ end
62
+
63
+ dispatcher.register_handler(target, 'failed') do |reason, details|
64
+ future.fail(reason, details)
65
+ end
66
+
67
+ future
68
+ end
69
+
70
+ def execute_activity!(activity_class, *input, **args)
71
+ future = execute_activity(activity_class, *input, **args)
72
+ result = future.get
73
+
74
+ if future.failed?
75
+ reason, details = result
76
+
77
+ error_class = safe_constantize(reason) || Cadence::ActivityException
78
+
79
+ raise error_class, details
80
+ end
81
+
82
+ result
83
+ end
84
+
85
+ # TODO: how to handle failures?
86
+ def execute_local_activity(activity_class, *input, **args)
87
+ input << args unless args.empty?
88
+
89
+ side_effect do
90
+ # TODO: this probably requires a local context implementation
91
+ context = Activity::Context.new(nil, nil)
92
+ activity_class.execute_in_context(context, input)
93
+ end
94
+ end
95
+
96
+ def execute_workflow(workflow_class, *input, **args)
97
+ options = args.delete(:options) || {}
98
+ input << args unless args.empty?
99
+
100
+ execution_options = ExecutionOptions.new(workflow_class, options)
101
+
102
+ decision = Decision::StartChildWorkflow.new(
103
+ workflow_id: options[:workflow_id] || SecureRandom.uuid,
104
+ workflow_type: execution_options.name,
105
+ input: input,
106
+ domain: execution_options.domain,
107
+ task_list: execution_options.task_list,
108
+ retry_policy: execution_options.retry_policy,
109
+ timeouts: execution_options.timeouts,
110
+ headers: execution_options.headers
111
+ )
112
+
113
+ target, cancelation_id = schedule_decision(decision)
114
+ future = Future.new(target, self, cancelation_id: cancelation_id)
115
+
116
+ dispatcher.register_handler(target, 'completed') do |result|
117
+ future.set(result)
118
+ future.callbacks.each { |callback| call_in_fiber(callback, result) }
119
+ end
120
+
121
+ dispatcher.register_handler(target, 'failed') do |reason, details|
122
+ future.fail(reason, details)
123
+ end
124
+
125
+ future
126
+ end
127
+
128
+ def execute_workflow!(workflow_class, *input, **args)
129
+ future = execute_workflow(workflow_class, *input, **args)
130
+ result = future.get
131
+
132
+ if future.failed?
133
+ reason, details = result
134
+
135
+ error_class = safe_constantize(reason) || StandardError.new(details)
136
+
137
+ raise error_class, details
138
+ end
139
+
140
+ result
141
+ end
142
+
143
+ def side_effect(&block)
144
+ marker = state_manager.next_side_effect
145
+ return marker.last if marker
146
+
147
+ result = block.call
148
+ decision = Decision::RecordMarker.new(name: StateManager::SIDE_EFFECT_MARKER, details: result)
149
+ schedule_decision(decision)
150
+
151
+ result
152
+ end
153
+
154
+ def sleep(timeout)
155
+ start_timer(timeout).wait
156
+ end
157
+
158
+ def sleep_until(end_time)
159
+ delay = (end_time.to_time - now).to_i
160
+ sleep(delay) if delay > 0
161
+ end
162
+
163
+ def start_timer(timeout, timer_id = nil)
164
+ decision = Decision::StartTimer.new(timeout: timeout, timer_id: timer_id)
165
+ target, cancelation_id = schedule_decision(decision)
166
+ future = Future.new(target, self, cancelation_id: cancelation_id)
167
+
168
+ dispatcher.register_handler(target, 'fired') do |result|
169
+ future.set(result)
170
+ future.callbacks.each { |callback| call_in_fiber(callback, result) }
171
+ end
172
+
173
+ dispatcher.register_handler(target, 'canceled') do |reason, details|
174
+ future.fail(reason, details)
175
+ end
176
+
177
+ future
178
+ end
179
+
180
+ def cancel_timer(timer_id)
181
+ decision = Decision::CancelTimer.new(timer_id: timer_id)
182
+ schedule_decision(decision)
183
+ end
184
+
185
+ # TODO: check if workflow can be completed
186
+ def complete(result = nil)
187
+ decision = Decision::CompleteWorkflow.new(result: result)
188
+ schedule_decision(decision)
189
+ end
190
+
191
+ # TODO: check if workflow can be failed
192
+ def fail(reason, details = nil)
193
+ decision = Decision::FailWorkflow.new(reason: reason, details: details)
194
+ schedule_decision(decision)
195
+ end
196
+
197
+ def wait_for_all(*futures)
198
+ futures.each(&:wait)
199
+
200
+ return
201
+ end
202
+
203
+ def wait_for(future)
204
+ fiber = Fiber.current
205
+
206
+ dispatcher.register_handler(future.target, Dispatcher::WILDCARD) do
207
+ fiber.resume if future.finished?
208
+ end
209
+
210
+ Fiber.yield
211
+
212
+ return
213
+ end
214
+
215
+ def now
216
+ state_manager.local_time
217
+ end
218
+
219
+ def on_signal(&block)
220
+ target = History::EventTarget.workflow
221
+
222
+ dispatcher.register_handler(target, 'signaled') do |signal, input|
223
+ call_in_fiber(block, signal, input)
224
+ end
225
+ end
226
+
227
+ def cancel_activity(activity_id)
228
+ decision = Decision::RequestActivityCancellation.new(activity_id: activity_id)
229
+
230
+ schedule_decision(decision)
231
+ end
232
+
233
+ def cancel(target, cancelation_id)
234
+ case target.type
235
+ when History::EventTarget::ACTIVITY_TYPE
236
+ cancel_activity(cancelation_id)
237
+ when History::EventTarget::TIMER_TYPE
238
+ cancel_timer(cancelation_id)
239
+ else
240
+ raise "#{target} can not be canceled"
241
+ end
242
+ end
243
+
244
+ private
245
+
246
+ attr_reader :state_manager, :dispatcher, :metadata
247
+
248
+ def schedule_decision(decision)
249
+ state_manager.schedule(decision)
250
+ end
251
+
252
+ def call_in_fiber(block, *args)
253
+ Fiber.new do
254
+ Cadence::ThreadLocalContext.set(self)
255
+ block.call(*args)
256
+ end.resume
257
+ end
258
+
259
+ def safe_constantize(const)
260
+ Object.const_get(const) if Object.const_defined?(const)
261
+ rescue NameError
262
+ nil
263
+ end
264
+ end
265
+ end
266
+ end