decider 0.10.0 → 2.0.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.

Potentially problematic release.


This version of decider might be problematic. Click here for more details.

data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Mike Skalnik
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,14 @@
1
+ = decider
2
+
3
+ After constantly opening up irb so that Ruby can make a decision for
4
+ me, I decided to make a tiny gem that makes deciding easy.
5
+
6
+ = Example
7
+ $ decider yes no
8
+ no
9
+ $ decider one two three
10
+ two
11
+
12
+ == Copyright
13
+
14
+ Copyright (c) 2009 Mike Skalnik. See LICENSE for details.
data/Rakefile CHANGED
@@ -1,10 +1,56 @@
1
- # frozen_string_literal: true
1
+ require 'rubygems'
2
+ require 'rake'
2
3
 
3
- require "bundler/gem_tasks"
4
- require "minitest/test_task"
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "decider"
8
+ gem.summary = %Q{A small gem that helps you decide between a few choices}
9
+ gem.email = "mike.skalnik@gmail.com"
10
+ gem.homepage = "http://github.com/skalnik/decider"
11
+ gem.authors = ["Mike Skalnik"]
12
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
13
+ end
5
14
 
6
- Minitest::TestTask.create
15
+ rescue LoadError
16
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
17
+ end
7
18
 
8
- require "standard/rake"
19
+ require 'rake/testtask'
20
+ Rake::TestTask.new(:test) do |test|
21
+ test.libs << 'lib' << 'test'
22
+ test.pattern = 'test/**/*_test.rb'
23
+ test.verbose = true
24
+ end
25
+
26
+ begin
27
+ require 'rcov/rcovtask'
28
+ Rcov::RcovTask.new do |test|
29
+ test.libs << 'test'
30
+ test.pattern = 'test/**/*_test.rb'
31
+ test.verbose = true
32
+ end
33
+ rescue LoadError
34
+ task :rcov do
35
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
36
+ end
37
+ end
38
+
39
+
40
+ task :default => :test
41
+
42
+ require 'rake/rdoctask'
43
+ Rake::RDocTask.new do |rdoc|
44
+ if File.exist?('VERSION.yml')
45
+ config = YAML.load(File.read('VERSION.yml'))
46
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
47
+ else
48
+ version = ""
49
+ end
50
+
51
+ rdoc.rdoc_dir = 'rdoc'
52
+ rdoc.title = "decider #{version}"
53
+ rdoc.rdoc_files.include('README*')
54
+ rdoc.rdoc_files.include('lib/**/*.rb')
55
+ end
9
56
 
10
- task default: %i[test standard]
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 2.0.0
data/bin/8ball ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'decider'
4
+
5
+ possible_results = ["Signs point to yes.",
6
+ "Yes.",
7
+ "Reply hazy, try again.",
8
+ "Without a doubt.",
9
+ "My sources say no.",
10
+ "As I see it, yes.",
11
+ "You may rely on it.",
12
+ "Concentrate and ask again.",
13
+ "Outlook not so good.",
14
+ "It is decidedly so.",
15
+ "Better not tell you now.",
16
+ "Very doubtful.",
17
+ "Yes - definitely.",
18
+ "It is certain.",
19
+ "Cannot predict now.",
20
+ "Most likely.",
21
+ "Ask again later.",
22
+ "My reply is no.",
23
+ "Outlook good.",
24
+ "Don't count on it."]
25
+ unless ARGV[0]
26
+ puts 'The 8 ball needs a question to answer!'
27
+ exit
28
+ end
29
+ puts Decider::decide *possible_results
data/bin/decider ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'decider'
4
+
5
+ puts Decider::decide *ARGV
data/lib/decider.rb CHANGED
@@ -1,392 +1,7 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "decider/reactor"
4
- require_relative "decider/view"
5
-
6
1
  module Decider
7
- StateAlreadyDefined = Class.new(StandardError)
8
- StateNotDefined = Class.new(StandardError)
9
-
10
- Pair = Data.define(:left, :right)
11
-
12
- class Left
13
- attr_reader :value
14
-
15
- def initialize(value)
16
- @value = value
17
- end
18
-
19
- def deconstruct
20
- [:left, value]
21
- end
22
-
23
- def ==(other)
24
- value == other.value
25
- end
2
+ extend self
3
+
4
+ def decide(*choices)
5
+ choices.shuffle[0]
26
6
  end
27
-
28
- class Right
29
- attr_reader :value
30
-
31
- def initialize(value)
32
- @value = value
33
- end
34
-
35
- def deconstruct
36
- [:right, value]
37
- end
38
-
39
- def ==(other)
40
- value == other.value
41
- end
42
- end
43
-
44
- class Module < ::Module
45
- DECIDE_FALLBACK = proc { [nil, proc {}] }
46
- EVOLVE_FALLBACK = proc { [nil, proc { state }] }
47
-
48
- Decide = Data.define(:command, :state, :_events) do
49
- def emit(*events)
50
- _events.push(*events)
51
- end
52
- end
53
- Evolve = Data.define(:state, :event) do
54
- def self.build(state, event)
55
- new(state: state, event: event)
56
- end
57
- end
58
- Terminal = Data.define(:state)
59
-
60
- def initialize(initial_state:, deciders:, evolutions:, terminal:)
61
- case initial_state
62
- in Proc
63
- define_method(:initial_state) do
64
- initial_state.call
65
- end
66
- else
67
- define_method(:initial_state) do
68
- initial_state
69
- end
70
- end
71
-
72
- define_method(:decide) do |command, state|
73
- context = Decide.new(command: command, state: state, _events: [])
74
-
75
- deciders.find(DECIDE_FALLBACK) do |args, _|
76
- case args
77
- in [Proc => fn]
78
- context.instance_exec(&fn)
79
- in [ctype]
80
- command in ^ctype
81
- in [ctype, stype]
82
- [command, state] in [^ctype, ^stype]
83
- else
84
- false
85
- end
86
- end => [_, handler]
87
-
88
- context.instance_exec(&handler)
89
- context._events
90
- end
91
-
92
- define_method(:evolve) do |*args|
93
- if args.empty?
94
- ->(state, event) { evolve(state, event) }
95
- else
96
- context = Evolve.build(*args)
97
-
98
- evolutions.find(EVOLVE_FALLBACK) do |args, _|
99
- case args
100
- in [Proc => fn]
101
- context.instance_exec(&fn)
102
- in [etype]
103
- context_event = context.event
104
- context_event in ^etype
105
- in [stype, etype]
106
- context_state = context.state
107
- context_event = context.event
108
- [context_state, context_event] in [^stype, ^etype]
109
- else
110
- false
111
- end
112
- end => [_, handler]
113
-
114
- context.instance_exec(&handler)
115
- end
116
- end
117
-
118
- define_method(:terminal?) do |state|
119
- context = Terminal.new(state: state)
120
-
121
- context.instance_exec(&terminal)
122
- end
123
-
124
- define_method(:lmap_on_command) do |fn|
125
- Decider.lmap_on_command(fn, self)
126
- end
127
-
128
- define_method(:lmap_on_state) do |fn|
129
- Decider.lmap_on_state(fn, self)
130
- end
131
-
132
- define_method(:map) do |fn|
133
- Decider.map(fn, self)
134
- end
135
-
136
- define_method(:rmap_on_state) do |fn|
137
- Decider.rmap_on_state(fn, self)
138
- end
139
-
140
- define_method(:dimap_on_state) do |fl:, fr:|
141
- Decider.dimap_on_state(fl, fr, self)
142
- end
143
-
144
- define_method(:lmap_on_event) do |fn|
145
- Decider.lmap_on_event(fn, self)
146
- end
147
-
148
- define_method(:rmap_on_event) do |fn|
149
- Decider.rmap_on_event(fn, self)
150
- end
151
-
152
- define_method(:dimap_on_event) do |fl:, fr:|
153
- Decider.dimap_on_event(fl, fr, self)
154
- end
155
-
156
- define_method(:many) do
157
- Decider.many(self)
158
- end
159
-
160
- define_method(:apply) do |f|
161
- Decider.apply(self, f)
162
- end
163
- end
164
- end
165
-
166
- class Builder
167
- DEFAULT = Object.new
168
-
169
- def initialize
170
- @initial_state = DEFAULT
171
- @deciders = {}
172
- @evolutions = {}
173
- @terminal = proc { false }
174
- end
175
-
176
- def build(&block)
177
- instance_exec(&block) if block_given?
178
-
179
- raise StateNotDefined if @initial_state == DEFAULT
180
-
181
- decider = Class.new
182
-
183
- mod = Module.new(
184
- initial_state: @initial_state,
185
- deciders: deciders,
186
- evolutions: evolutions,
187
- terminal: terminal
188
- )
189
-
190
- decider.extend(mod)
191
-
192
- decider
193
- end
194
-
195
- private
196
-
197
- attr_reader :deciders, :evolutions, :terminal
198
-
199
- def initial_state(state = DEFAULT, &block)
200
- raise StateAlreadyDefined if @initial_state != DEFAULT
201
-
202
- @initial_state =
203
- if block_given?
204
- block
205
- else
206
- state
207
- end
208
- end
209
-
210
- def decide(*args, &block)
211
- deciders[args] = block
212
- end
213
-
214
- def evolve(*args, &block)
215
- evolutions[args] = block
216
- end
217
-
218
- def terminal?(&block)
219
- @terminal = block
220
- end
221
- end
222
- private_constant :Builder
223
-
224
- def self.define(&block)
225
- builder = Builder.new
226
- builder.build(&block)
227
- end
228
-
229
- def self.compose(left, right)
230
- define do
231
- initial_state Pair.new(
232
- left: left.initial_state,
233
- right: right.initial_state
234
- )
235
-
236
- decide proc { command in [:left, _] } do
237
- left.decide(command.value, state.left).each { emit Left.new(_1) }
238
- end
239
-
240
- decide proc { command in [:right, _] } do
241
- right.decide(command.value, state.right).each { emit Right.new(_1) }
242
- end
243
-
244
- evolve proc { event in [:left, _] } do
245
- state.with(
246
- left: left.evolve(state.left, event.value)
247
- )
248
- end
249
-
250
- evolve proc { event in [:right, _] } do
251
- state.with(
252
- right: right.evolve(state.right, event.value)
253
- )
254
- end
255
-
256
- terminal? do
257
- left.terminal?(state.left) && right.terminal?(state.right)
258
- end
259
- end
260
- end
261
-
262
- def self.lmap_on_command(fn, decider)
263
- define do
264
- initial_state decider.initial_state
265
-
266
- decide proc { true } do
267
- decider.decide(fn.call(command), state).each(&method(:emit))
268
- end
269
-
270
- evolve proc { true } do
271
- decider.evolve(state, event)
272
- end
273
-
274
- terminal? do
275
- decider.terminal?(state)
276
- end
277
- end
278
- end
279
-
280
- def self.lmap_on_state(fn, decider)
281
- dimap_on_state(fn, ->(state) { state }, decider)
282
- end
283
-
284
- def self.map(fn, decider)
285
- dimap_on_state(->(state) { state }, fn, decider)
286
- end
287
-
288
- def self.rmap_on_state(fn, decider)
289
- dimap_on_state(->(state) { state }, fn, decider)
290
- end
291
-
292
- def self.dimap_on_state(fl, fr, decider)
293
- define do
294
- initial_state fr.call(decider.initial_state)
295
-
296
- decide proc { true } do
297
- decider.decide(command, fl.call(state)).each(&method(:emit))
298
- end
299
-
300
- evolve proc { true } do
301
- fr.call(decider.evolve(fl.call(state), event))
302
- end
303
-
304
- terminal? do
305
- decider.terminal?(fl.call(state))
306
- end
307
- end
308
- end
309
-
310
- def self.lmap_on_event(fn, decider)
311
- dimap_on_event(fn, ->(event) { event }, decider)
312
- end
313
-
314
- def self.rmap_on_event(fn, decider)
315
- dimap_on_event(->(event) { event }, fn, decider)
316
- end
317
-
318
- def self.dimap_on_event(fl, fr, decider)
319
- define do
320
- initial_state decider.initial_state
321
-
322
- decide proc { true } do
323
- decider.decide(command, state).each do |event|
324
- emit fr.call(event)
325
- end
326
- end
327
-
328
- evolve proc { true } do
329
- decider.evolve(state, fl.call(event))
330
- end
331
-
332
- terminal? do
333
- decider.terminal?(state)
334
- end
335
- end
336
- end
337
-
338
- def self.many(decider)
339
- define do
340
- initial_state({})
341
-
342
- decide proc { [command, state] in [[_id, _], Hash] } do
343
- command => [id, command]
344
-
345
- ds = state.fetch(id) { decider.initial_state }
346
-
347
- decider.decide(command, ds).each do |event|
348
- emit [id, event]
349
- end
350
- end
351
-
352
- evolve proc { [state, event] in [Hash, [_id, _]] } do
353
- event => [id, event]
354
-
355
- ds = state.fetch(id) { decider.initial_state }
356
- ds = decider.evolve(ds, event)
357
-
358
- state.merge(id => ds)
359
- end
360
-
361
- terminal? do
362
- state.any? && state.all? { |_, ds| decider.terminal?(ds) }
363
- end
364
- end
365
- end
366
-
367
- def self.apply(f, x)
368
- map2(->(f, x) { f.call(x) }, f, x)
369
- end
370
-
371
- def self.map2(fn, dx, dy)
372
- define do
373
- initial_state fn.call(dx.initial_state, dy.initial_state)
374
-
375
- decide proc { true } do
376
- dx.decide(command, state).each(&method(:emit))
377
- dy.decide(command, state).each(&method(:emit))
378
- end
379
-
380
- evolve proc { true } do
381
- fn.call(
382
- dx.evolve(state, event),
383
- dy.evolve(state, event)
384
- )
385
- end
386
-
387
- terminal? do
388
- dx.terminal?(state) && dy.terminal?(state)
389
- end
390
- end
391
- end
392
- end
7
+ end
@@ -0,0 +1,12 @@
1
+ require 'test_helper'
2
+
3
+ class DeciderTest < Test::Unit::TestCase
4
+ should "pick the the only choice if given one" do
5
+ assert_equal 'one', Decider::decide('one')
6
+ end
7
+
8
+ should "pick one of the given choices" do
9
+ choices = ['one', 'two', 'three']
10
+ assert_contains choices, Decider::decide(*choices)
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'decider'
8
+
9
+ class Test::Unit::TestCase
10
+ end