Module: Obfusk

Defined in:
lib/obfusk/adt.rb,
lib/obfusk/atom.rb,
lib/obfusk/data.rb,
lib/obfusk/lazy.rb,
lib/obfusk/list.rb,
lib/obfusk/monad.rb,
lib/obfusk/monads.rb,
lib/obfusk/version.rb

Defined Under Namespace

Modules: ADT, Monad, MonadPlus, Monads Classes: Atom, List

Constant Summary collapse

ADT_Meta__ =
{ inheriting: [false], mutex: Mutex.new }
VERSION =
'0.1.3'
DATE =
'2014-06-18'

Class Method Summary collapse

Class Method Details

.atom(value) ⇒ Object

create an Atom



39
40
41
# File 'lib/obfusk/atom.rb', line 39

def self.atom(value)
  Atom.new value
end

.eager(x) ⇒ Object

eager: evaluate if lazy, just return if not



35
36
37
# File 'lib/obfusk/lazy.rb', line 35

def self.eager(x)
  lazy?(x) ? x._ : x
end

.get_in(o, *ks, &b) ⇒ Object

get nested key in nested datastructure



42
43
44
# File 'lib/obfusk/data.rb', line 42

def self.get_in(o, *ks, &b)
  ks.each { |k| o = o.fetch(k) { return b ? b[] : nil } }; o
end

.lazy(x = nil, &b) ⇒ Object

lazy evaluation (thunk)



16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/obfusk/lazy.rb', line 16

def self.lazy(x = nil, &b)
  return x if lazy? x
  f = b ? b : -> { x }; v = nil; e = false
  g = -> () { unless e then v = f[]; e = true end; v }
  g.define_singleton_method(:__obfusk_lazy__?) { true }
  g.define_singleton_method(:_)     { g[] }
  g.define_singleton_method(:deref) { g[] }
  g.define_singleton_method(:chain) do |m,*a,&b|
    ::Obfusk::lazy { g[].public_send(m,*a,&b) }
  end
  g
end

.lazy?(x) ⇒ Boolean

lazy?

Returns:

  • (Boolean)


30
31
32
# File 'lib/obfusk/lazy.rb', line 30

def self.lazy?(x)
  x.respond_to?(:__obfusk_lazy__?) && x.__obfusk_lazy__?
end

.List(*xs, &b) ⇒ Object

create a list from its items; pass a block to add a lazy tail



250
251
252
253
254
255
# File 'lib/obfusk/list.rb', line 250

def self.List(*xs, &b)
  b && xs.length == 1 ? Cons(xs.first, &b)  :
  b && xs.empty?      ? b._                 :
  xs.empty?           ? Nil()               :
  Cons(xs.first) { List(*xs.drop(1), &b) }
end

.merge(x, h = {}) ⇒ Object

merge anything that responds to .__obfusk_merge__ or .merge



30
31
32
# File 'lib/obfusk/data.rb', line 30

def self.merge(x, h = {})
  x.respond_to?(:__obfusk_merge__) ? x.__obfusk_merge__(h) : x.merge(h)
end

.merge!(x, h = {}) ⇒ Object

merge anything that responds to .__obfusk_merge__! or .merge!



35
36
37
# File 'lib/obfusk/data.rb', line 35

def self.merge!(x, h = {})
  x.respond_to?(:__obfusk_merge__!) ? x.__obfusk_merge__!(h) : x.merge!(h)
end

.modify_in(o, k, *ks, &b) ⇒ Object

swap value for nested key in nested datastructure; autovivifies missing keys as hashes

Returns:

  • a new datastructure



49
50
51
52
# File 'lib/obfusk/data.rb', line 49

def self.modify_in(o, k, *ks, &b)
  ks_ = [k] + ks; os = nested_objects o, *ks_; o_ = b[os.pop]
  ks_.reverse.each { |k| o_ = merge(os.pop, k => o_) }; o_
end

.modify_in!(o, k, *ks, &b) ⇒ Object

swap value for nested key in nested datastructure; autovivifies missing keys as hashes

Returns:

  • modified datastructure



57
58
59
60
# File 'lib/obfusk/data.rb', line 57

def self.modify_in!(o, k, *ks, &b)
  ks_ = [k] + ks; os = nested_objects o, *ks_; o_ = b[os.pop]
  ks_.reverse.each { |k| o_ = merge!(os.pop, k => o_) }; o_
end

.nested_objects(o, *ks) ⇒ Object

get stack of objects for nested key in nested datastructure; autovivifies missing keys as hashes



64
65
66
# File 'lib/obfusk/data.rb', line 64

def self.nested_objects(o, *ks)
  [o] + ks.map { |k| o = o.fetch(k) { {} } }
end

.set_in(o, *ks, v) ⇒ Object

set value for nested key in nested datastructure

Returns:

  • a new datastructure



70
71
72
# File 'lib/obfusk/data.rb', line 70

def self.set_in(o, *ks, v)
  modify_in(o, *ks) { |_| v }
end

.set_in!(o, *ks, v) ⇒ Object

set value for nested key in nested datastructure

Returns:

  • modified datastructure



76
77
78
# File 'lib/obfusk/data.rb', line 76

def self.set_in!(o, *ks, v)
  modify_in!(o, *ks) { |_| v }
end