rns 0.0.2 → 0.0.3

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.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rns (0.0.2)
4
+ rns (0.0.3)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
data/README.md CHANGED
@@ -24,10 +24,8 @@ module Statistics
24
24
  end
25
25
 
26
26
  class Main
27
- include Rns
28
-
29
- extend_specified Arithmetic => [:inc]
30
- include_specified Statistics => [:avg]
27
+ extend Rns.module_with(Arithmetic => [:inc])
28
+ include Rns.module_with(Statistics => [:avg])
31
29
 
32
30
  def main
33
31
  puts "1+1 is #{self.class.inc 1} and the average of [1,2,3] is #{avg [1,2,3]}"
data/lib/rns/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Rns
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
data/lib/rns.rb CHANGED
@@ -1,41 +1,47 @@
1
1
  module Rns
2
- def self.included(base)
3
- base.extend(ClassMethods)
4
- end
2
+ class << self
3
+ def constant_for(module_names)
4
+ (m, *more) = module_names.map{|n| n.split("::")}.flatten
5
+ more.reduce(Kernel.const_get(m)){|m, s| m.const_get(s)}
6
+ end
5
7
 
6
- def self.add_methods(to, use_spec)
7
- use_spec.to_a.each do |from, method_names|
8
- if (method_names.is_a? Hash)
9
- add_methods(to, method_names.map do |k,v|
10
- #TODO: is there a better way to construct modules?
11
- {eval(from.to_s + "::" + k.to_s) => v}
12
- end.reduce({}){|l,r| l.merge(r)})
13
- else
14
- method_names.each do |name|
15
- if (name.is_a? Hash)
16
- add_methods(to, {from => name})
17
- else
18
- to.send(:define_method, name) do |*args|
19
- from.method(name).call(*args)
20
- end
21
- end
8
+ def module_with(use_spec)
9
+ Module.new.tap {|m| add_methods(m, use_spec) }
10
+ end
11
+
12
+ def process_spec_entry(entry)
13
+ (k,v) = entry
14
+ if (v.is_a? Array)
15
+ v.map{|x| process_spec_entry([k,x])}
16
+ elsif (v.is_a? Hash)
17
+ v.map do |x,y|
18
+ process_spec_entry([constant_for([k, x].map(&:to_s)), y])
22
19
  end
20
+ else
21
+ [k,v]
23
22
  end
24
23
  end
25
- end
26
24
 
27
- module ClassMethods
28
- def include_specified(use_spec)
29
- Rns::add_methods(self, use_spec)
25
+ def process_spec(use_spec)
26
+ use_spec.map(&method(:process_spec_entry)).
27
+ flatten.
28
+ each_slice(2).
29
+ to_a
30
30
  end
31
31
 
32
- def extend_specified(use_spec)
33
- singleton_class = class << self; self; end
34
- Rns::add_methods(singleton_class, use_spec)
32
+ def add_methods(to, use_spec)
33
+ process_spec(use_spec).each do |from, method|
34
+ to.send(:define_method, method) do |*args|
35
+ from.method(method).call(*args)
36
+ end
37
+ to.send(:private, method)
38
+ end
35
39
  end
36
- end
37
40
 
38
- def self.using(use_spec, &blk)
39
- blk[Object.new.tap{|o| Rns::add_methods(o.class, use_spec)}]
41
+ def using(use_spec, &blk)
42
+ klass = Class.new
43
+ add_methods(klass, use_spec)
44
+ klass.new.instance_eval(&blk)
45
+ end
40
46
  end
41
47
  end
data/spec/rns/rns_spec.rb CHANGED
@@ -8,6 +8,7 @@ module Math
8
8
  class << self
9
9
  def dec(n) n - one end
10
10
  def inc(n) n + one end
11
+ def add(x,y) x + y end
11
12
  private
12
13
  def one() 1 end
13
14
  end
@@ -15,17 +16,40 @@ module Math
15
16
 
16
17
  module Statistics
17
18
  def self.avg(arr); arr.reduce(:+).to_f / arr.count end
19
+ module Foo
20
+ def self.blah; :quux end
21
+ end
18
22
  end
19
23
  end
20
24
 
21
- class Thing
22
- include Rns
25
+ module Util
26
+ class << self
27
+ def assoc!(h, k, v)
28
+ h.tap{|o| o[k] = v}
29
+ end
23
30
 
24
- extend_specified Math::Arithmetic => [:inc]
25
- include_specified Math::Statistics => [:avg]
31
+ def merge_with(f, *hshs)
32
+ merge_entry = lambda do |h, (k,v)|
33
+ if (h.has_key?(k))
34
+ assoc!(h, k, f[h[k], v])
35
+ else
36
+ assoc!(h, k, v)
37
+ end
38
+ end
39
+ merge2 = lambda do |h1,h2|
40
+ h2.to_a.reduce(h1, &merge_entry)
41
+ end
42
+ ([{}] + hshs).reduce(&merge2)
43
+ end
44
+ end
45
+ end
26
46
 
27
- def inced_one
28
- self.class.inc 1
47
+ class Thing
48
+ extend Rns.module_with(Math::Arithmetic => [:inc])
49
+ include Rns.module_with(Math::Statistics => [:avg])
50
+
51
+ def self.inced_one
52
+ inc 1
29
53
  end
30
54
 
31
55
  def average
@@ -40,11 +64,33 @@ describe Rns do
40
64
  end
41
65
 
42
66
  it "works with private module methods" do
43
- Thing.new.inced_one.should == 2
67
+ Thing.inced_one.should == 2
68
+ end
69
+
70
+ it "should add methods privately" do
71
+ lambda { Thing.new.avg [11, 42, 7] }.should raise_error(NoMethodError)
44
72
  end
45
73
  end
46
74
 
47
75
  context 'adding methods to blocks' do
76
+
77
+ it 'computes' do
78
+ Rns::using(Util => [:merge_with],
79
+ Math::Arithmetic => [:inc, :add]) do
80
+
81
+ sum = lambda{|*xs| xs.reduce(:+)}
82
+
83
+ merge_with(sum, *(1..10).map{|n| {x: n}})[:x].should == 55
84
+ merge_with(sum,
85
+ {x: 10, y: 20},
86
+ {x: 3, z: 30}).should == {x: 13, y: 20, z: 30}
87
+
88
+ merge_with(lambda{|l,r| l.send(:+, r)},
89
+ {:x => [:something]},
90
+ {:x => [:else]}).should == {:x => [:something, :else]}
91
+ end
92
+ end
93
+
48
94
  it "works with individual modules" do
49
95
  Rns::using(Math::Arithmetic => [:inc],
50
96
  Math::Statistics => [:avg]) do
@@ -68,5 +114,38 @@ describe Rns do
68
114
  avg((1..10).to_a.map(&method(:inc))).should == 6.5
69
115
  end
70
116
  end
117
+
118
+ it "does not modify Object" do
119
+ Rns::using(Math::Arithmetic => [:inc]) do
120
+ # do nothing
121
+ end
122
+ lambda { Object.new.inc 1 }.should raise_error(NoMethodError)
123
+ end
124
+
125
+ it "does not modify Class" do
126
+ Rns::using(Math::Arithmetic => [:inc]) do
127
+ # do nothing
128
+ end
129
+ lambda { Class.new.inc 1 }.should raise_error(NoMethodError)
130
+ end
131
+
132
+ it 'processes specs correctly' do
133
+ Rns::using(Rns => [:process_spec]) do
134
+ process_spec({Math => [:inc, :dec]}).
135
+ should == [[Math, :inc], [Math, :dec]]
136
+ end
137
+
138
+ Rns::using(Rns => [:process_spec]) do
139
+ spec = {Math::Arithmetic => [:inc],
140
+ Math => [:identity,
141
+ {:Statistics => [:avg,
142
+ {:Foo => [:blah, :quux]}]}]}
143
+ process_spec(spec).should == [[Math::Arithmetic, :inc],
144
+ [Math, :identity],
145
+ [Math::Statistics, :avg],
146
+ [Math::Statistics::Foo, :blah],
147
+ [Math::Statistics::Foo, :quux]]
148
+ end
149
+ end
71
150
  end
72
151
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rns
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-06 00:00:00.000000000 Z
12
+ date: 2012-05-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec