lspace 0.1 → 0.2

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/.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