agrippa 0.0.1

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.
@@ -0,0 +1,12 @@
1
+ require "agrippa/proxy"
2
+
3
+ module Agrippa
4
+ class State < Proxy
5
+ def method_missing(method, *args, &block)
6
+ output = @value.send(method, *args, &block)
7
+ return(output) unless proxied_method?(method)
8
+ @value = output
9
+ self
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module Agrippa
2
+ module Utilities
3
+ def self.try_require(file, fail_message = nil)
4
+ begin
5
+ require(file)
6
+ rescue LoadError => error
7
+ return(false) if fail_message.nil?
8
+ raise(LoadError, fail_message)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ module Agrippa
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,146 @@
1
+ require "spec_helper"
2
+ require "agrippa/delegation"
3
+ require "agrippa/mutable"
4
+ require "agrippa/immutable"
5
+
6
+ RSpec.describe Agrippa::Delegation do
7
+ let(:klass) { Class.new.send(:include, Agrippa::Delegation) }
8
+
9
+ let(:instance) { klass.new }
10
+
11
+ describe ".delegate" do
12
+ describe "to a method" do
13
+ let(:receiver) { double(ping: "pong", bing: "bong") }
14
+
15
+ before(:each) { klass.send(:attr_accessor, :target) }
16
+
17
+ it "without a prefix" do
18
+ expect(receiver).to receive(:ping)
19
+ klass.delegate(:ping, to: :target)
20
+ instance.target = receiver
21
+ expect(instance.ping).to eq("pong")
22
+ end
23
+
24
+ it "with default prefix" do
25
+ expect(receiver).to receive(:ping)
26
+ klass.delegate(:ping, to: :target, prefix: true)
27
+ instance.target = receiver
28
+ expect(instance.target_ping).to eq("pong")
29
+ end
30
+
31
+ it "with custom prefix" do
32
+ expect(receiver).to receive(:ping)
33
+ klass.delegate(:ping, to: :target, prefix: "mister")
34
+ instance.target = receiver
35
+ expect(instance.mister_ping).to eq("pong")
36
+ end
37
+
38
+ it "with default suffix" do
39
+ expect(receiver).to receive(:ping)
40
+ klass.delegate(:ping, to: :target, suffix: true)
41
+ instance.target = receiver
42
+ expect(instance.ping_target).to eq("pong")
43
+ end
44
+
45
+ it "with custom suffix" do
46
+ expect(receiver).to receive(:ping)
47
+ klass.delegate(:ping, to: :target, suffix: "mister")
48
+ instance.target = receiver
49
+ expect(instance.ping_mister).to eq("pong")
50
+ end
51
+
52
+ it "accepts strings" do
53
+ expect(receiver).to receive(:ping)
54
+ klass.delegate("ping", to: :target)
55
+ instance.target = receiver
56
+ expect(instance.ping).to eq("pong")
57
+ end
58
+
59
+ it "multiple methods" do
60
+ expect(receiver).to receive(:ping)
61
+ klass.delegate(*%w(ping bing), to: :target)
62
+ instance.target = receiver
63
+ expect(instance.ping).to eq("pong")
64
+ expect(instance.bing).to eq("bong")
65
+ end
66
+
67
+ end
68
+
69
+ it "to the class" do
70
+ klass.delegate(:ping, to: :class)
71
+ receiver = Module.new
72
+ receiver.send(:define_method, :ping) { "class pong" }
73
+ klass.send(:extend, receiver)
74
+ expect(instance.ping).to eq("class pong")
75
+ end
76
+ end
77
+
78
+ describe ".class_delegate" do
79
+ let(:receiver) { double(ping: "pong") }
80
+
81
+ before(:each) do
82
+ klass.class_eval("class << self; attr_accessor :target; end")
83
+ klass.target = receiver
84
+ end
85
+
86
+ it "without a prefix" do
87
+ expect(receiver).to receive(:ping)
88
+ klass.class_delegate(:ping, to: :target)
89
+ expect(klass.ping).to eq("pong")
90
+ end
91
+
92
+ it "with default prefix" do
93
+ expect(receiver).to receive(:ping)
94
+ klass.class_delegate(:ping, to: :target, prefix: true)
95
+ expect(klass.target_ping).to eq("pong")
96
+ end
97
+
98
+ it "with custom prefix" do
99
+ expect(receiver).to receive(:ping)
100
+ klass.class_delegate(:ping, to: :target, prefix: "mister")
101
+ expect(klass.mister_ping).to eq("pong")
102
+ end
103
+
104
+ it "with default suffix" do
105
+ expect(receiver).to receive(:ping)
106
+ klass.class_delegate(:ping, to: :target, suffix: true)
107
+ expect(klass.ping_target).to eq("pong")
108
+ end
109
+
110
+ it "with custom suffix" do
111
+ expect(receiver).to receive(:ping)
112
+ klass.class_delegate(:ping, to: :target, suffix: "mister")
113
+ expect(klass.ping_mister).to eq("pong")
114
+ end
115
+ end
116
+
117
+ describe ".delegate_command" do
118
+ let(:klass) do
119
+ result = Class.new.send(:include, Agrippa::Delegation)
120
+ .send(:include, Agrippa::Mutable)
121
+ .state_accessor(:target)
122
+ end
123
+
124
+ let(:instance) { klass.new }
125
+
126
+ let(:receiver_class) do
127
+ Class.new.send(:include, Agrippa::Immutable)
128
+ .state_accessor(:value)
129
+ end
130
+
131
+ let(:receiver) { receiver_class.new }
132
+
133
+ let(:random_value) { Object.new }
134
+
135
+ it "delegates" do
136
+ klass.delegate_command(:set_value, to: :target)
137
+ instance.set_target(receiver)
138
+ expect(instance.target).to be(receiver)
139
+ result = instance.set_value(random_value)
140
+ expect(result).to be(instance)
141
+ expect(instance.target).to be_a(receiver_class)
142
+ expect(instance.target).to_not be(receiver)
143
+ expect(instance.target.value).to be(random_value)
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,23 @@
1
+ require "spec_helper"
2
+ require "shared/state_container_examples"
3
+ require "agrippa/immutable"
4
+
5
+ RSpec.describe Agrippa::Immutable do
6
+ let(:klass) { Class.new.send(:include, Agrippa::Immutable) }
7
+
8
+ it_behaves_like "a state container"
9
+
10
+ it "#store does not mutate" do
11
+ instance = klass.new(a: 1)
12
+ expect(instance.store(:b, 2)).to_not be(instance)
13
+ end
14
+
15
+ describe "#new" do
16
+ it "directly uses Hamster::Hash" do
17
+ initial_state = Hamster::Hash.new(a: 1)
18
+ instance = klass.new(initial_state)
19
+ final_state = instance.instance_variable_get(:@state)
20
+ expect(final_state).to be(initial_state)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,32 @@
1
+ require "spec_helper"
2
+ require "agrippa/maybe"
3
+
4
+ RSpec.describe Agrippa::Maybe do
5
+ it "handles nils" do
6
+ instance = double(call: nil)
7
+ expect(instance).to receive(:call)
8
+ proxy = Agrippa::Maybe.new(instance)
9
+ expect { proxy.call }.to_not raise_error
10
+ expect { proxy.call }.to_not raise_error
11
+ expect(proxy._value).to be_nil
12
+ end
13
+
14
+ it "handles unknown methods" do
15
+ instance = Object.new
16
+ proxy = Agrippa::Maybe.new(instance)
17
+ expect { proxy.call }.to_not raise_error
18
+ expect(proxy._value).to be_nil
19
+ end
20
+
21
+ it "chains" do
22
+ finish = double(call: 42)
23
+ start = double(call: finish)
24
+ expect(start).to receive(:call)
25
+ expect(finish).to receive(:call)
26
+ proxy = Agrippa::Maybe.new(start)
27
+ expect { proxy.call }.to_not raise_error
28
+ expect(proxy._value).to eq(finish)
29
+ expect { proxy.call }.to_not raise_error
30
+ expect(proxy._value).to eq(42)
31
+ end
32
+ end
@@ -0,0 +1,38 @@
1
+ require "spec_helper"
2
+ require "agrippa/methods"
3
+
4
+ RSpec.describe Agrippa::Methods do
5
+ let(:klass) { Class.new.send(:include, Agrippa::Methods) }
6
+
7
+ describe ".command_methods" do
8
+ def methods
9
+ klass.command_methods
10
+ end
11
+
12
+ it "empty by default" do
13
+ expect(methods).to be_empty
14
+ end
15
+
16
+ describe "adds methods" do
17
+ it "single string" do
18
+ klass.mark_as_commands "foo"
19
+ expect(methods).to eq(foo: true)
20
+ end
21
+
22
+ it "single symbol" do
23
+ klass.mark_as_commands :foo
24
+ expect(methods).to eq(foo: true)
25
+ end
26
+
27
+ it "list of symbols" do
28
+ klass.mark_as_commands :foo, :bar
29
+ expect(methods).to eq(foo: true, bar: true)
30
+ end
31
+
32
+ it "array of strings" do
33
+ klass.mark_as_commands %w(foo bar)
34
+ expect(methods).to eq(foo: true, bar: true)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,14 @@
1
+ require "spec_helper"
2
+ require "shared/state_container_examples"
3
+ require "agrippa/mutable_hash"
4
+
5
+ RSpec.describe Agrippa::MutableHash do
6
+ let(:klass) { Class.new.send(:include, Agrippa::MutableHash) }
7
+
8
+ it_behaves_like "a state container"
9
+
10
+ it "#store mutates" do
11
+ instance = klass.new(a: 1)
12
+ expect(instance.store(:b, 2)).to be(instance)
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ require "spec_helper"
2
+ require "shared/state_container_examples"
3
+ require "agrippa/mutable"
4
+
5
+ RSpec.describe Agrippa::Mutable do
6
+ let(:klass) { Class.new.send(:include, Agrippa::Mutable) }
7
+
8
+ it_behaves_like "a state container"
9
+
10
+ it "#store mutates" do
11
+ instance = klass.new(a: 1)
12
+ expect(instance.store(:b, 2)).to be(instance)
13
+ end
14
+ end
@@ -0,0 +1,38 @@
1
+ require "spec_helper"
2
+ require "agrippa/mutable"
3
+ require "agrippa/mutable_hash"
4
+ require "agrippa/immutable"
5
+ require "shared/state_container_examples"
6
+
7
+ RSpec.describe Agrippa::Mutable do
8
+ let(:klass) { Class.new.send(:include, Agrippa::Mutable) }
9
+
10
+ it_behaves_like "a state container"
11
+
12
+ it "#store mutates" do
13
+ instance = klass.new(a: 1)
14
+ expect(instance.store(:b, 2)).to be(instance)
15
+ end
16
+ end
17
+
18
+ RSpec.describe Agrippa::MutableHash do
19
+ let(:klass) { Class.new.send(:include, Agrippa::MutableHash) }
20
+
21
+ it_behaves_like "a state container"
22
+
23
+ it "#store mutates" do
24
+ instance = klass.new(a: 1)
25
+ expect(instance.store(:b, 2)).to be(instance)
26
+ end
27
+ end
28
+
29
+ RSpec.describe Agrippa::Immutable do
30
+ let(:klass) { Class.new.send(:include, Agrippa::Immutable) }
31
+
32
+ it_behaves_like "a state container"
33
+
34
+ it "#store does not mutate" do
35
+ instance = klass.new(a: 1)
36
+ expect(instance.store(:b, 2)).to_not be(instance)
37
+ end
38
+ end
@@ -0,0 +1,107 @@
1
+ require "spec_helper"
2
+ require "agrippa/proxy"
3
+ require "agrippa/methods"
4
+
5
+ RSpec.describe Agrippa::Proxy do
6
+ let(:klass) { Class.new }
7
+
8
+ let(:instance) { klass.new }
9
+
10
+ it "requires subclasses to implement method_missing" do
11
+ proxy = Agrippa::Proxy.new(instance)
12
+ expect { proxy.foo }.to raise_error(NoMethodError)
13
+ end
14
+
15
+ describe "proxied methods" do
16
+ it "everything by default" do
17
+ proxy = Agrippa::Proxy.new(instance)
18
+ expect(proxy.proxied_method?(:foo)).to be(true)
19
+ end
20
+
21
+ it "specified only" do
22
+ proxy = Agrippa::Proxy.new(instance, :a, "b")
23
+ expect(proxy.proxied_methods).to eq(a: true, b: true)
24
+ expect(proxy.proxied_method?(:c)).to be(false)
25
+ end
26
+
27
+ it "command" do
28
+ klass.send(:include, Agrippa::Methods)
29
+ klass.mark_as_command(:a)
30
+ proxy = Agrippa::Proxy.new(instance)
31
+ expect(proxy.proxied_methods).to eq(a: true)
32
+ end
33
+
34
+ it "both specified and command" do
35
+ klass.send(:include, Agrippa::Methods)
36
+ klass.mark_as_command(:a)
37
+ proxy = Agrippa::Proxy.new(instance, :b)
38
+ expect(proxy.proxied_methods).to eq(a: true, b: true)
39
+ end
40
+ end
41
+
42
+ it "#is_a? wrapped class" do
43
+ proxy = Agrippa::Proxy.new(instance)
44
+ expect(proxy.is_a?(klass)).to be(true)
45
+ end
46
+
47
+ it "#is_a? proxy" do
48
+ proxy = Agrippa::Proxy.new(instance)
49
+ expect(proxy.is_a?(Agrippa::Proxy)).to be(true)
50
+ end
51
+
52
+ it "#respond_to? proxy" do
53
+ proxy = Agrippa::Proxy.new(instance)
54
+ expect(proxy.respond_to?(:proxied_methods)).to be(true)
55
+ expect(proxy.respond_to?(:total_bullshit)).to be(false)
56
+ end
57
+
58
+ it "#respond_to? wrapped" do
59
+ instance = double(ping: "pong")
60
+ proxy = Agrippa::Proxy.new(instance)
61
+ expect(proxy.respond_to?(:ping)).to be(true)
62
+ expect(proxy.respond_to?(:pong)).to be(false)
63
+ end
64
+
65
+ it "#_value" do
66
+ inner_class = Class.new(Agrippa::Proxy)
67
+ outer_class = Class.new(Agrippa::Proxy)
68
+ instance = double()
69
+ inner = inner_class.new(instance)
70
+ outer = outer_class.new(inner)
71
+ expect(outer._value.__id__).to eq(inner.__id__)
72
+ end
73
+
74
+ it "#_ returns #_value" do
75
+ inner_class = Class.new(Agrippa::Proxy)
76
+ outer_class = Class.new(Agrippa::Proxy)
77
+ instance = double()
78
+ inner = inner_class.new(instance)
79
+ outer = outer_class.new(inner)
80
+ expect(outer._.__id__).to eq(outer._value.__id__)
81
+ end
82
+
83
+ it "#_deep_value" do
84
+ inner_class = Class.new(Agrippa::Proxy)
85
+ outer_class = Class.new(Agrippa::Proxy)
86
+ instance = double()
87
+ inner = inner_class.new(instance)
88
+ outer = outer_class.new(inner)
89
+ expect(outer._deep_value).to be(instance)
90
+ end
91
+
92
+ it "proxies" do
93
+ passthrough = Module.new do
94
+ def method_missing(name, *args, &block)
95
+ @value.send(name, *args, &block)
96
+ end
97
+ end
98
+ inner_class = Class.new(Agrippa::Proxy)
99
+ .send(:include, passthrough)
100
+ outer_class = Class.new(Agrippa::Proxy)
101
+ .send(:include, passthrough)
102
+ instance = double(ping: "pong")
103
+ inner = inner_class.new(instance)
104
+ outer = outer_class.new(inner)
105
+ expect(outer.ping).to eq("pong")
106
+ end
107
+ end