lspace 0.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/README.md CHANGED
@@ -19,7 +19,7 @@ class DatabaseConnection
19
19
  end
20
20
 
21
21
  def self.use_master(&block)
22
- LSpace.update(:preferred_connection => master_connection) do
22
+ LSpace.with(:preferred_connection => master_connection) do
23
23
  block.call
24
24
  end
25
25
  end
@@ -69,11 +69,11 @@ class Fetcher
69
69
  end
70
70
 
71
71
  EM::run do
72
- LSpace.update(:log_prefix => rand(50000)) do
72
+ LSpace.with(:log_prefix => rand(50000)) do
73
73
  Fetcher.new.fetch("http://www.google.com")
74
74
  Fetcher.new.fetch("http://www.yahoo.com")
75
75
  end
76
- LSpace.update(:log_prefix => rand(50000)) do
76
+ LSpace.with(:log_prefix => rand(50000)) do
77
77
  Fetcher.new.fetch("http://www.microsoft.com")
78
78
  end
79
79
  end
@@ -19,13 +19,14 @@ class LSpace
19
19
  enter new({}, nil), &block
20
20
  end
21
21
 
22
- # Create a new LSpace with the given keys set to the given values.
22
+ # Create a new LSpace with the given keys set to the given values, and run the
23
+ # given block in that new LSpace.
23
24
  #
24
25
  # The LSpace will inherit any unspecified keys from the currently active LSpace.
25
26
  #
26
27
  # @example
27
- # LSpace.update :user_id => 6 do
28
- # LSpace.update :job_id => 7 do
28
+ # LSpace.with :user_id => 6 do
29
+ # LSpace.with :job_id => 7 do
29
30
  # LSpace[:user_id] == 6
30
31
  # LSpace[:job_id] == 7
31
32
  # end
@@ -34,7 +35,7 @@ class LSpace
34
35
  # @param [Hash] hash The keys to update
35
36
  # @param [Proc] block The logical block to run with the updated LSpace
36
37
  # @see LSpace.enter
37
- def self.update(hash={}, &block)
38
+ def self.with(hash={}, &block)
38
39
  enter new(hash, current), &block
39
40
  end
40
41
 
@@ -66,7 +67,7 @@ class LSpace
66
67
  previous = current
67
68
  self.current = lspace
68
69
 
69
- filters = lspace.hierarchy.take_while{ |lspace| lspace != previous }.map(&:around_filters).flatten
70
+ filters = lspace.hierarchy.take_while{ |lspace| lspace != previous }.flat_map(&:around_filters)
70
71
 
71
72
  filters.inject(block) do |blk, filter|
72
73
  lambda{ filter.call(&blk) }
@@ -15,7 +15,7 @@ class Module
15
15
  # LSpace[:user_id] = 6
16
16
  # Job.new.user == #<User:6>
17
17
  #
18
- # @param [Symbol] *attrs The accessors to create
18
+ # @param [Symbol] attrs The accessors to create
19
19
  def lspace_reader(*attrs)
20
20
  attrs.each do |attr|
21
21
  define_method(attr) do
@@ -29,7 +29,7 @@ class Module
29
29
  # This wraps both the &block parameter, and also any Procs
30
30
  # that are passed into the function directly.
31
31
  #
32
- # If you need more complicated logic (i.e. wrapping Procs
32
+ # If you need more complicated logic (e.g. wrapping Procs
33
33
  # that are passed to a function in a dictionary) you're
34
34
  # on your own.
35
35
  #
@@ -42,17 +42,20 @@ class Module
42
42
  # Thread.new{ LSpace[:user_id] == 2 }
43
43
  # end
44
44
  #
45
- # @param [Symbol] *methods The methods to wrap
45
+ # @param [Symbol] methods The methods to wrap
46
46
  def in_lspace(*methods)
47
47
  methods.each do |method|
48
48
  method_without_lspace = "#{method}_without_lspace"
49
+
50
+ # Idempotence: do nothing if the _without_lspace method already exists.
51
+ # method_defined? matches public and protected methods; private methods need a separate check.
49
52
  next if method_defined?(method_without_lspace) || private_method_defined?(method_without_lspace)
50
53
 
51
54
  alias_method method_without_lspace, method
52
55
 
53
56
  define_method(method) do |*args, &block|
54
57
  args.map!{ |a| Proc === a ? a.in_lspace : a }
55
- block = block && block.in_lspace
58
+ block = block.in_lspace if block
56
59
  __send__(method_without_lspace, *args, &block)
57
60
  end
58
61
 
@@ -63,7 +66,8 @@ class Module
63
66
  end
64
67
 
65
68
  class Proc
66
- # Preserve LSpace when this Proc is run.
69
+ # Preserve LSpace when this Proc is run. Returns a new Proc, a closure that
70
+ # re-enters the current LSpace when it is called.
67
71
  #
68
72
  # @example
69
73
  # todo = LSpace.new :user_id => 2 do
@@ -1,5 +1,8 @@
1
1
  require 'eventmachine'
2
2
  require 'lspace'
3
+
4
+ # Optional module to make EventMachine preserve LSpaces in its event callbacks. Not loaded by
5
+ # default; you must +require 'lspace/eventmachine'+ to use it.
3
6
  module EventMachine
4
7
 
5
8
  # Most of the low-level EventMachine stuff goes through singleton methods on the
@@ -20,7 +23,7 @@ module EventMachine
20
23
  class Connection
21
24
 
22
25
  class << self
23
- # As EM uses a custom implementation of {new}, the only sane way to
26
+ # As EM uses a custom implementation of new, the only sane way to
24
27
  # set up the LSpace in advance is to override allocate.
25
28
  alias_method :allocate_without_lspace, :allocate
26
29
  end
@@ -28,11 +31,11 @@ module EventMachine
28
31
  # Overridden allocate which sets up a new LSpace.
29
32
  #
30
33
  # Each connection object is run in its own LSpace, which can be
31
- # configured by implementing the {setup_lspace} method.
34
+ # configured by implementing the {Connection#setup_lspace} method.
32
35
  def self.allocate
33
36
  allocate_without_lspace.instance_eval do
34
37
  extend EventMachine::LSpacePreserver
35
- LSpace.update do
38
+ LSpace.with do
36
39
  setup_lspace
37
40
  @lspace = LSpace.current
38
41
  end
data/lib/lspace.rb CHANGED
@@ -5,7 +5,7 @@ require File.expand_path('../lspace/class_methods', __FILE__)
5
5
  # application's purpose, but still necessary.
6
6
  #
7
7
  # In many ways they are the successor to the Thread-local namespace, but they are designed
8
- # to be active during a logical segment of code no-matter how you slice that code amoungst
8
+ # to be active during a logical segment of code, no matter how you slice that code amongst
9
9
  # different Threads or Fibers.
10
10
  #
11
11
  # The API for LSpace encourages creating a new sub-LSpace whenever you want to mutate the
@@ -15,7 +15,7 @@ require File.expand_path('../lspace/class_methods', __FILE__)
15
15
  #
16
16
  # @example
17
17
  # require 'lspace/thread'
18
- # LSpace.update(:job_id => 1) do
18
+ # LSpace.with(:job_id => 1) do
19
19
  # Thread.new do
20
20
  # puts "processing #{LSpace[:job_id]}"
21
21
  # end.join
@@ -47,8 +47,8 @@ class LSpace
47
47
  # of parent LSpaces. If the key is not found anywhere, nil is returned.
48
48
  #
49
49
  # @example
50
- # LSpace.update :user_id => 5 do
51
- # LSpace.update :user_id => 6 do
50
+ # LSpace.with :user_id => 5 do
51
+ # LSpace.with :user_id => 6 do
52
52
  # LSpace[:user_id] == 6
53
53
  # end
54
54
  # end
@@ -65,7 +65,7 @@ class LSpace
65
65
  # Update the LSpace-variable with the given name.
66
66
  #
67
67
  # Bear in mind that any code using this LSpace will see this change, and consider
68
- # using {LSpace.update} instead to localize your changes.
68
+ # using {LSpace.with} instead to localize your changes.
69
69
  #
70
70
  # This method is mostly useful for setting up a new LSpace before any code is
71
71
  # using it, and has no effect on parent LSpaces.
@@ -116,7 +116,7 @@ class LSpace
116
116
  LSpace.enter(self, &block)
117
117
  end
118
118
 
119
- # Ensure that the Proc runs in this LSpace
119
+ # Wraps a block/proc such that it runs in this LSpace when it is called.
120
120
  #
121
121
  # @see Proc#in_lspace
122
122
  # @see LSpace.preserve
data/lspace.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "lspace"
3
- s.version = "0.1"
3
+ s.version = "0.2"
4
4
  s.platform = Gem::Platform::RUBY
5
5
  s.author = "Conrad Irwin"
6
6
  s.email = "conrad.irwin@gmail.com"
@@ -12,5 +12,6 @@ Gem::Specification.new do |s|
12
12
 
13
13
  s.add_development_dependency 'rspec'
14
14
  s.add_development_dependency 'pry-rescue'
15
+ s.add_development_dependency 'pry-stack_explorer'
15
16
  s.add_development_dependency 'eventmachine'
16
17
  end
@@ -18,16 +18,16 @@ describe LSpace do
18
18
  end
19
19
  end
20
20
 
21
- describe ".update" do
21
+ describe ".with" do
22
22
  it "should enter a new LSpace with the new variables set" do
23
- LSpace.update(:foo => 5) do
23
+ LSpace.with(:foo => 5) do
24
24
  LSpace[:foo].should == 5
25
25
  end
26
26
  end
27
27
 
28
28
  it "should enter a new LSpace which delegates to the current parent" do
29
- LSpace.update(:foo => 5) do
30
- LSpace.update(:bar => 4) do
29
+ LSpace.with(:foo => 5) do
30
+ LSpace.with(:bar => 4) do
31
31
  LSpace[:foo].should == 5
32
32
  end
33
33
  end
@@ -36,7 +36,7 @@ describe LSpace do
36
36
 
37
37
  describe ".clean" do
38
38
  it "should enter a new LSpace with no parent" do
39
- LSpace.update(:foo => 5) do
39
+ LSpace.with(:foo => 5) do
40
40
  LSpace.clean do
41
41
  LSpace[:foo].should == nil
42
42
  end
@@ -45,7 +45,7 @@ describe LSpace do
45
45
  end
46
46
 
47
47
  describe ".enter" do
48
- it "should update LSpace.current" do
48
+ it "should with LSpace.current" do
49
49
  LSpace.enter(@lspace) do
50
50
  LSpace.current.should == @lspace
51
51
  end
@@ -5,7 +5,7 @@ describe Module do
5
5
  it "should define a reader for LSpace" do
6
6
  klass = Class.new{ lspace_reader :user_id }
7
7
 
8
- LSpace.update(:user_id => 8) do
8
+ LSpace.with(:user_id => 8) do
9
9
  klass.new.user_id.should == 8
10
10
  end
11
11
  end
@@ -40,7 +40,7 @@ describe Module do
40
40
  end
41
41
 
42
42
  it "should automatically preserve LSpace for blocks that are passed in" do
43
- @task = LSpace.update :user_id => 6 do
43
+ @task = LSpace.with :user_id => 6 do
44
44
  @klass.new{ LSpace[:user_id] }
45
45
  end
46
46
 
@@ -48,7 +48,7 @@ describe Module do
48
48
  end
49
49
 
50
50
  it "should automatically preserve LSpace for procs that are passed in" do
51
- @task = LSpace.update :user_id => 6 do
51
+ @task = LSpace.with :user_id => 6 do
52
52
  @klass.new proc{ LSpace[:user_id] }
53
53
  end
54
54
 
@@ -59,13 +59,22 @@ describe Module do
59
59
  @klass.private_method_defined?(:private_test).should == true
60
60
  @klass.protected_method_defined?(:protected_test).should == true
61
61
  end
62
+
63
+ it "should be idempotent" do
64
+ @klass.in_lspace :initialize
65
+
66
+ LSpace.with :user_id => 9 do
67
+ @task = @klass.new{ LSpace[:user_id] }
68
+ end
69
+ @task.call.should == 9
70
+ end
62
71
  end
63
72
  end
64
73
 
65
74
  describe Proc do
66
75
  describe "#in_lspace" do
67
76
  it "should create a wrapper which preserves the LSpace" do
68
- p = LSpace.update(:job_id => 19) do
77
+ p = LSpace.with(:job_id => 19) do
69
78
  lambda{ LSpace[:job_id] }.in_lspace
70
79
  end
71
80
 
@@ -8,7 +8,7 @@ describe LSpace do
8
8
 
9
9
  it "should preserve LSpace in deferrable callbacks" do
10
10
  d = Class.new{ include EM::Deferrable }.new
11
- LSpace.update(:foo => 2) do
11
+ LSpace.with(:foo => 2) do
12
12
  d.callback do
13
13
  $foo = LSpace[:foo]
14
14
  end
@@ -19,7 +19,7 @@ describe LSpace do
19
19
 
20
20
  it "should preserve LSpace in deferrable errbacks" do
21
21
  d = Class.new{ include EM::Deferrable }.new
22
- LSpace.update(:foo => 2) do
22
+ LSpace.with(:foo => 2) do
23
23
  d.errback do
24
24
  $foo = LSpace[:foo]
25
25
  end
@@ -30,7 +30,7 @@ describe LSpace do
30
30
 
31
31
  it "should preserve LSpace in EM::defer operation" do
32
32
  EM::run do
33
- LSpace.update(:foo => 4) do
33
+ LSpace.with(:foo => 4) do
34
34
  EM::defer(lambda{
35
35
  $foo = LSpace[:foo]
36
36
  }, proc{
@@ -43,7 +43,7 @@ describe LSpace do
43
43
 
44
44
  it "should preserve LSpace in EM::defer callback" do
45
45
  EM::run do
46
- LSpace.update(:foo => 4) do
46
+ LSpace.with(:foo => 4) do
47
47
  EM::defer(lambda{
48
48
  nil
49
49
  }, proc{
@@ -58,7 +58,7 @@ describe LSpace do
58
58
  it "should preserve LSpace in EM.next_tick" do
59
59
  EM::run do
60
60
  EM::next_tick do
61
- LSpace.update :foo => 5 do
61
+ LSpace.with :foo => 5 do
62
62
  EM::next_tick do
63
63
  $foo = LSpace[:foo]
64
64
  EM::stop
@@ -117,7 +117,7 @@ describe LSpace do
117
117
  end
118
118
  end
119
119
 
120
- LSpace.update(:bar => :baz) do
120
+ LSpace.with(:bar => :baz) do
121
121
  EM::run do
122
122
  EM::start_server '0.0.0.0', 9345, server
123
123
  EM::connect '127.0.0.1', 9345, client
data/spec/lspace_spec.rb CHANGED
@@ -124,6 +124,7 @@ describe LSpace do
124
124
  end
125
125
 
126
126
  it "should revert the changed LSpace at the end of the block" do
127
+ LSpace.current.should_not == @lspace
127
128
  lspace = LSpace.current
128
129
  @lspace.wrap{ LSpace.current.should == @lspace }.call
129
130
  LSpace.current.should == lspace
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lspace
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.1'
4
+ version: '0.2'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -43,6 +43,22 @@ dependencies:
43
43
  - - ! '>='
44
44
  - !ruby/object:Gem::Version
45
45
  version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: pry-stack_explorer
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
46
62
  - !ruby/object:Gem::Dependency
47
63
  name: eventmachine
48
64
  requirement: !ruby/object:Gem::Requirement
@@ -65,6 +81,8 @@ executables: []
65
81
  extensions: []
66
82
  extra_rdoc_files: []
67
83
  files:
84
+ - .gitignore
85
+ - Gemfile
68
86
  - LICENSE.MIT
69
87
  - README.md
70
88
  - lib/lspace.rb