context-filters 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9f1809572fcd86c5f8ee99f43c956fa4ebbba43b
4
- data.tar.gz: a4c0c942c34bcabfb2193b2d8f59cb2fa2bcf23e
3
+ metadata.gz: 83448fa38442792fe4a30024c26e0e992cd67edc
4
+ data.tar.gz: 37f4cbb3444f2f9365d922c86fc6ecd87cf2504a
5
5
  SHA512:
6
- metadata.gz: 5b0f70e4be2fbf8c869f8be48a9ac20d9051b7c757d1cdad9f822e5242ab7ef432be7ef117a073bd2cae76a7ee2337f55c7ba157affe239e3f46420b63e09fe9
7
- data.tar.gz: 1274b880b437e254e86c98027a30efa26175ae57758d135b786a0b5383d3d434cdc70b500c23a76c36eed0abbad5ef17b87423396d6c10cf55a94f98a08ea5a9
6
+ metadata.gz: 1b3a3cc9145e049c9ac4908230a7101c66cfbe0ce9ad5cfef6624c87606ab0cb2907854d9b3f06ad26d70814755dd52f6e58ab09f14eeb48b1504c249b5a86f4
7
+ data.tar.gz: 77ae68c8e7f0fba6778b2674fabbe7b09acb108a4e7bc103465cc6d36e3b9c44fe82c007c2b6f6418e4478ca01016d8ade5ef397ef53aa056e7b7f2386dd44ae
@@ -4,14 +4,20 @@ Copyright 2014 Michal Papis <mpapis@gmail.com>
4
4
  See the file LICENSE for copying permission.
5
5
  =end
6
6
 
7
- require "context-filters/global_context"
8
- require "context-filters/local_context"
7
+ require "context-filters/context/global"
8
+ require "context-filters/context/local"
9
9
 
10
10
  # manipulate set of context and filters for it,
11
11
  # allow evaluating filters in given context
12
- class ContextFilters::Context < ContextFilters::GlobalContext
12
+ class ContextFilters::Context
13
13
 
14
- include ContextFilters::LocalContext
14
+ include ContextFilters::Context::Global
15
+ include ContextFilters::Context::Local
16
+
17
+ # sets up the priorities order for global context filters
18
+ def initialize(priority_filters = nil)
19
+ initialize_priority_filters(priority_filters)
20
+ end
15
21
 
16
22
  # run the given method on global and local filters
17
23
  # @param method [Proc] the method to evaluate for filters matching context
@@ -0,0 +1,43 @@
1
+ =begin
2
+ Copyright 2014 Michal Papis <mpapis@gmail.com>
3
+
4
+ See the file LICENSE for copying permission.
5
+ =end
6
+
7
+ require "context-filters/context/global_context"
8
+ require "context-filters/context/global_filters"
9
+
10
+ class ContextFilters::Context
11
+
12
+ # builds list of filters and provides dsl for building nested context
13
+ # and allows evaluating filters on methods in the current context
14
+ module Global
15
+
16
+ include GlobalContext
17
+ include GlobalFilters
18
+
19
+ # evaluates all matching filters for given context_stack, allows to do extra
20
+ # work for +priority.nil?+ or on the end of the priorities,
21
+ #
22
+ # @param method [Proc] the method to evaluate with filters matching current context
23
+ # @yield on first +priority.nil?+ or on the end when none
24
+ def evaluate_filters(target, method)
25
+ local_called = false
26
+
27
+ priority_filters.each do |priority, filters|
28
+
29
+ context_stack.each { |options| filters.apply(target, method, options) }
30
+
31
+ if priority.nil? && block_given? && !local_called
32
+ yield
33
+ local_called = true
34
+ end
35
+
36
+ end
37
+
38
+ yield if block_given? && !local_called
39
+ end
40
+
41
+ end
42
+
43
+ end
@@ -0,0 +1,34 @@
1
+ =begin
2
+ Copyright 2014 Michal Papis <mpapis@gmail.com>
3
+
4
+ See the file LICENSE for copying permission.
5
+ =end
6
+
7
+ require "context-filters/version"
8
+
9
+ class ContextFilters::Context
10
+
11
+ # temporarily stack context and yield code
12
+ module GlobalContext
13
+
14
+ # @return [Array] the context stack
15
+ # @api private
16
+ def context_stack
17
+ @context_stack ||= [nil]
18
+ end
19
+
20
+ # starts new context
21
+ # @param options [Object] options to start new context
22
+ # @param block [Proc] code block that will enable filtering for the given +options+
23
+ # @yield a block in which +context_stack+ temporarily includes +filter_block+
24
+ # @yieldparam [self] use it optionally to give a new name to the
25
+ # code evaluated in new context
26
+ def context(options, &block)
27
+ context_stack.push(options)
28
+ yield(self)
29
+ ensure
30
+ context_stack.pop
31
+ end
32
+ end
33
+
34
+ end
@@ -0,0 +1,39 @@
1
+ =begin
2
+ Copyright 2014 Michal Papis <mpapis@gmail.com>
3
+
4
+ See the file LICENSE for copying permission.
5
+ =end
6
+
7
+ require "context-filters/filters/priority_filters"
8
+
9
+ class ContextFilters::Context
10
+
11
+ # simple access to global priority filters
12
+ module GlobalFilters
13
+
14
+ # @return [PriorityFilters] shared list of filters
15
+ # @api private
16
+ def priority_filters
17
+ @priority_filters ||= initialize_priority_filters(nil)
18
+ end
19
+
20
+ # sets up the priorities order for filters
21
+ # @param priority_filters [Array] initialization param for PriorityFilters
22
+ # @api private
23
+ def initialize_priority_filters(priority_filters)
24
+ @priority_filters = ContextFilters::Filters::PriorityFilters.new(priority_filters)
25
+ end
26
+
27
+ # defines new filter for given +priority+ and +options+
28
+ #
29
+ # @param priority [nil, Object] has to correspond to one of the initialized priorities
30
+ # @param options [Object] the options to use for new filter
31
+ # @param block [Proc] the transformation to use when the options match
32
+ #
33
+ def filter(priority, options = nil, &block)
34
+ priority_filters.store(priority, options, &block)
35
+ end
36
+
37
+ end
38
+
39
+ end
@@ -0,0 +1,43 @@
1
+ =begin
2
+ Copyright 2014 Michal Papis <mpapis@gmail.com>
3
+
4
+ See the file LICENSE for copying permission.
5
+ =end
6
+
7
+ require "context-filters/version"
8
+
9
+ class ContextFilters::Context
10
+
11
+ # allow defining local filters and evaluating code in context of thems
12
+ module Local
13
+
14
+ # @return [Array<Proc>] list of blocks to evaluate
15
+ # @api private
16
+ def local_filters
17
+ @local_filters ||= []
18
+ end
19
+
20
+ # temporarly adds +filter_block+ to the list of filters to run and
21
+ # yields given block of code
22
+ #
23
+ # @param filter_block [Proc] a block of code to add to the list
24
+ # @yield a block in which +local_filters+ temporarily includes +filter_block+
25
+ def local_filter(filter_block, &block)
26
+ local_filters.push(filter_block)
27
+ block.call
28
+ ensure
29
+ local_filters.pop
30
+ end
31
+
32
+ # iterates over +local_filters+ and applies them to the given +method+
33
+ #
34
+ # @param method [Proc] a method to call with each filter stored in
35
+ # +local_filters+
36
+ # @api private
37
+ def evaluate_local_filters(target, method)
38
+ local_filters.each { |block| target.send(method, &block) }
39
+ end
40
+
41
+ end
42
+
43
+ end
@@ -0,0 +1,72 @@
1
+ =begin
2
+ Copyright 2014 Michal Papis <mpapis@gmail.com>
3
+
4
+ See the file LICENSE for copying permission.
5
+ =end
6
+
7
+ require "context-filters/filters/store"
8
+
9
+ # filtering related classes and modules
10
+ module ContextFilters::Filters
11
+
12
+ # Store and apply filters using blocks
13
+ #
14
+ # @example
15
+ #
16
+ # class FiltersTestSubject
17
+ # attr_reader :value
18
+ # def initialize(value)
19
+ # @value = value
20
+ # end
21
+ # def change(&block)
22
+ # @value = block.call(@value)
23
+ # end
24
+ # end
25
+ # filters = ContextFilters::Filters.new
26
+ # filters.store(:addition) {|value| value + 1 }
27
+ # filters.store(:subtraction) {|value| value - 1 }
28
+ # filters.filters # => [:addition, :subtraction]
29
+ # object = FiltersTestSubject.new(3)
30
+ # object.value => 3
31
+ # filters.apply(object.method(:change), :addition)
32
+ # object.value => 4
33
+ # filters.apply(object.method(:change), :subtraction)
34
+ # object.value => 3
35
+
36
+ class Filters
37
+
38
+ include Store
39
+
40
+ # applies matching filters to the given target method, also uses
41
+ # filters matching extra +:target => target+ when options is a Hash
42
+ # @param target [Object] an object to run the method on
43
+ # @param method [symbol] method name that takes a transformation
44
+ # block as param
45
+ # @param options [Object] a filter for selecting matching blocks
46
+ def apply(target, method, options = nil)
47
+ select_filters(target, options).each{|block| target.send(method, &block) }
48
+ end
49
+
50
+ # Select matching filters and filters including targets when
51
+ # options is a +Hash+
52
+ # @param target [Object] an object to run the method on
53
+ # @param options [Object] a filter for selecting matching blocks
54
+ def select_filters(target, options)
55
+ found = filters_store.fetch(options, [])
56
+ if
57
+ Hash === options || options.nil?
58
+ then
59
+ options ||={}
60
+ options.merge!(:target => target)
61
+ found +=
62
+ # can not @filters.fetch(options, []) to allow filters provide custom ==()
63
+ filters_store.select do |filter_options, filters|
64
+ options == filter_options
65
+ end.map(&:last).flatten
66
+ end
67
+ found
68
+ end
69
+
70
+ end
71
+
72
+ end
@@ -0,0 +1,57 @@
1
+ =begin
2
+ Copyright 2014 Michal Papis <mpapis@gmail.com>
3
+
4
+ See the file LICENSE for copying permission.
5
+ =end
6
+
7
+ require "context-filters/filters/filters"
8
+
9
+ module ContextFilters::Filters
10
+
11
+ # list of +filters+ sorted by +priorities+
12
+ class PriorityFilters
13
+
14
+ # @return [Array] list of priorities this object was initialized with
15
+ attr_reader :priorities
16
+
17
+ # initializes priorities and coresponding list of filters
18
+ # @param priorities [Array|Object] a list of priorities to order filters
19
+ def initialize(priorities = nil)
20
+ @priorities = [priorities].flatten.freeze
21
+ @filters_array = @priorities.product([Filters.new])
22
+ end
23
+
24
+ # adds a priority filter
25
+ #
26
+ # @param priority [Object] anything that was part of +priorities+ array
27
+ # @param options [Object] forwarded to Filters.store
28
+ # @param block [Proc] forwarded to Filters.store
29
+ # @raise [KeyError] when priority not matching priorities is used
30
+ def store(priority, options = nil, &block)
31
+ found = @filters_array.assoc(priority)
32
+ raise KeyError if found.nil?
33
+ found.last.store(options, &block)
34
+ end
35
+
36
+ # list of +filters+ sorted by +priorities+
37
+ def to_a
38
+ @filters_array
39
+ end
40
+
41
+ # iterate over +filters+ ordered by +priority+
42
+ # @yield [priority,filters] the next filters from sorted array
43
+ # @yieldparam priority [Object] the priority
44
+ # @yieldparam filters [Filters] the filters for priority
45
+ def each(&block)
46
+ to_a.each(&block) unless empty?
47
+ end
48
+
49
+ # check if all of the filters are empty
50
+ # return [Bolean] true if all filters are empty
51
+ def empty?
52
+ @filters_array.map(&:last).all?(&:empty?)
53
+ end
54
+
55
+ end
56
+
57
+ end
@@ -0,0 +1,43 @@
1
+ =begin
2
+ Copyright 2014 Michal Papis <mpapis@gmail.com>
3
+
4
+ See the file LICENSE for copying permission.
5
+ =end
6
+
7
+ require "context-filters/version"
8
+
9
+ # filtering related classes and modules
10
+ module ContextFilters::Filters
11
+
12
+ # Store filters
13
+ module Store
14
+
15
+ # @return [Hash] the filters storage
16
+ # @api private
17
+ def filters_store
18
+ @filters_store ||= {}
19
+ end
20
+
21
+ # stores the block for given options, if the options have a block
22
+ # already the new one is added to the list
23
+ # @param options [Object] options for filtering blocks
24
+ # @param block [Proc] block of code to add to the list of blocks
25
+ # for this options
26
+ def store(options = nil, &block)
27
+ filters_store[options] ||= []
28
+ filters_store[options] << block
29
+ end
30
+
31
+ # Array of already defined filters
32
+ def filters
33
+ filters_store.keys
34
+ end
35
+
36
+ # @return [Boolean] true if there are any rules stored, false otherwise
37
+ def empty?
38
+ filters_store.empty?
39
+ end
40
+
41
+ end
42
+
43
+ end
@@ -1,5 +1,5 @@
1
1
  # Build command text based on multiple filters
2
2
  class ContextFilters
3
3
  # version of the context-filters gem
4
- VERSION = "0.10.0"
4
+ VERSION = "0.11.0"
5
5
  end
@@ -0,0 +1,36 @@
1
+ =begin
2
+ Copyright 2014 Michal Papis <mpapis@gmail.com>
3
+
4
+ See the file LICENSE for copying permission.
5
+ =end
6
+
7
+ require "test_helper"
8
+ require "context-filters/context/global_context"
9
+
10
+ describe ContextFilters::Context::GlobalContext do
11
+
12
+ subject do
13
+ Object.new.tap { |o| o.extend(ContextFilters::Context::GlobalContext) }
14
+ end
15
+
16
+ it "sets up initial variables" do
17
+ subject.context_stack.must_equal([nil])
18
+ end
19
+
20
+ it "nests context" do
21
+ subject.context(:a) do |test_a|
22
+
23
+ test_a.object_id.must_equal(subject.object_id)
24
+ test_a.context_stack.must_equal([nil, :a])
25
+
26
+ test_a.context(:b) do |test_b|
27
+ test_b.object_id.must_equal(test_a.object_id)
28
+ test_b.context_stack.must_equal([nil, :a, :b])
29
+ end
30
+
31
+ test_a.context_stack.must_equal([nil, :a])
32
+ end
33
+ subject.context_stack.must_equal([nil])
34
+ end
35
+
36
+ end
@@ -0,0 +1,32 @@
1
+ =begin
2
+ Copyright 2014 Michal Papis <mpapis@gmail.com>
3
+
4
+ See the file LICENSE for copying permission.
5
+ =end
6
+
7
+ require "test_helper"
8
+ require "context-filters/context/global_filters"
9
+
10
+ describe ContextFilters::Context::GlobalFilters do
11
+
12
+ subject do
13
+ Object.new.tap { |o| o.extend(ContextFilters::Context::GlobalFilters) }
14
+ end
15
+
16
+ it "sets up empty initial variables" do
17
+ subject.priority_filters.must_be_kind_of ContextFilters::Filters::PriorityFilters
18
+ subject.priority_filters.must_be_empty
19
+ end
20
+
21
+ it "initializes new PriorityFilters" do
22
+ example = [:a, :b, :c]
23
+ subject.initialize_priority_filters(example)
24
+ subject.priority_filters.priorities.must_equal(example)
25
+ end
26
+
27
+ it "stores filters" do
28
+ subject.priority_filters.expects(:store).with(nil, :a).once
29
+ subject.filter(nil, :a) do true end
30
+ end
31
+
32
+ end
@@ -0,0 +1,54 @@
1
+ =begin
2
+ Copyright 2014 Michal Papis <mpapis@gmail.com>
3
+
4
+ See the file LICENSE for copying permission.
5
+ =end
6
+
7
+ require "test_helper"
8
+ require "context-filters/context/global"
9
+ require "context-filters/filter_test_subject"
10
+
11
+ describe ContextFilters::Context::Global do
12
+
13
+ subject do
14
+ Object.new.tap { |o| o.extend(ContextFilters::Context::Global) }
15
+ end
16
+
17
+ let(:filter_test_subject) do
18
+ FilterTestSubject.new(3)
19
+ end
20
+
21
+ it "does not apply filters when no filters" do
22
+ subject.priority_filters.expects(:apply).never
23
+ subject.evaluate_filters(filter_test_subject, :change)
24
+ end
25
+
26
+ it "does apply filters" do
27
+ method = Proc.new{}
28
+ subject.context_stack << :a
29
+ subject.filter(nil, :b) { true }
30
+ subject.priority_filters.to_a[0][1].expects(:apply).once.with(filter_test_subject, :change, nil)
31
+ subject.priority_filters.to_a[0][1].expects(:apply).once.with(filter_test_subject, :change, :a)
32
+ subject.evaluate_filters(filter_test_subject, :change)
33
+ end
34
+
35
+ it "does apply targeted filters in top context" do
36
+ addition = Proc.new { |value| value+1 }
37
+ multiplication = Proc.new { |value| value*3 }
38
+ subject.filter(nil, {:target => filter_test_subject}, &addition)
39
+ subject.filter(nil, {:target => nil}, &multiplication)
40
+ subject.evaluate_filters(filter_test_subject, :change)
41
+ filter_test_subject.value.must_equal(4)
42
+ end
43
+
44
+ it "does apply targeted filters in sub context" do
45
+ addition = Proc.new { |value| value+1 }
46
+ multiplication = Proc.new { |value| value*3 }
47
+ subject.context_stack << { :a => 1 }
48
+ subject.filter(nil, {:a => 1, :target => filter_test_subject}, &addition)
49
+ subject.filter(nil, {:a => 1, :target => nil}, &multiplication)
50
+ subject.evaluate_filters(filter_test_subject, :change)
51
+ filter_test_subject.value.must_equal(4)
52
+ end
53
+
54
+ end
@@ -5,13 +5,13 @@ See the file LICENSE for copying permission.
5
5
  =end
6
6
 
7
7
  require "test_helper"
8
- require "context-filters/local_context"
8
+ require "context-filters/context/local"
9
9
  require "context-filters/filter_test_subject"
10
10
 
11
- describe ContextFilters::LocalContext do
11
+ describe ContextFilters::Context::Local do
12
12
 
13
13
  subject do
14
- Object.new.tap { |o| o.extend(ContextFilters::LocalContext) }
14
+ Object.new.tap { |o| o.extend(ContextFilters::Context::Local) }
15
15
  end
16
16
 
17
17
  let(:filter_test_subject) do
@@ -10,16 +10,35 @@ require "context-filters/filter_test_subject"
10
10
 
11
11
  describe ContextFilters::Context do
12
12
 
13
- subject do
14
- ContextFilters::Context.new
15
- end
13
+ describe "#initialize" do
16
14
 
17
- let(:filter_test_subject) do
18
- FilterTestSubject.new(3)
19
- end
15
+ subject do
16
+ ContextFilters::Context.allocate
17
+ end
18
+
19
+ it "initializes empty priority_filters" do
20
+ subject.send(:initialize)
21
+ subject.priority_filters.priorities.must_equal([nil])
22
+ end
23
+
24
+ it "initializes priority_filters with values" do
25
+ example = [:a, :b, :c]
26
+ subject.send(:initialize, example)
27
+ subject.priority_filters.priorities.must_equal(example)
28
+ end
29
+
30
+ end #initialize
20
31
 
21
32
  describe "#evaluate_filters" do
22
33
 
34
+ subject do
35
+ ContextFilters::Context.new
36
+ end
37
+
38
+ let(:filter_test_subject) do
39
+ FilterTestSubject.new(3)
40
+ end
41
+
23
42
  it "does not apply filters when no filters" do
24
43
  subject.priority_filters.expects(:apply).never
25
44
  subject.evaluate_filters(filter_test_subject, :change)
@@ -5,51 +5,15 @@ See the file LICENSE for copying permission.
5
5
  =end
6
6
 
7
7
  require "test_helper"
8
- require "context-filters/filters"
8
+ require "context-filters/filters/filters"
9
9
  require "context-filters/filter_test_subject"
10
10
 
11
- describe ContextFilters::Filters do
11
+ describe ContextFilters::Filters::Filters do
12
12
 
13
13
  subject do
14
- ContextFilters::Filters.new
14
+ ContextFilters::Filters::Filters.new
15
15
  end
16
16
 
17
- describe "#store" do
18
-
19
- it "adds empty filter" do
20
- subject.store() { true }
21
- subject.filters.size.must_equal 1
22
- subject.filters.first.must_equal(nil)
23
- end
24
-
25
- it "adds options filter" do
26
- subject.store(x: 2) { true }
27
- subject.filters.size.must_equal 1
28
- subject.filters.first.must_equal({x:2})
29
- end
30
-
31
- it "adds hash filter" do
32
- subject.store({x: 3}) { true }
33
- subject.filters.size.must_equal 1
34
- subject.filters.first.must_equal({x:3})
35
- end
36
-
37
- it "adds nil filter" do
38
- subject.store(nil) { true }
39
- subject.filters.size.must_equal 1
40
- subject.filters.first.must_equal(nil)
41
- end
42
-
43
- it "adds filter block" do
44
- subject.store() { 4 }
45
- filters = subject.instance_variable_get(:@filters)
46
- filters.size.must_equal 1
47
- filters[nil].size.must_equal 1
48
- filters[nil].first.call.must_equal(4)
49
- end
50
-
51
- end #store
52
-
53
17
  describe "#apply" do
54
18
 
55
19
  let(:apply_test_subject) do
@@ -5,12 +5,12 @@ See the file LICENSE for copying permission.
5
5
  =end
6
6
 
7
7
  require "test_helper"
8
- require "context-filters/priority_filters"
8
+ require "context-filters/filters/priority_filters"
9
9
 
10
- describe ContextFilters::PriorityFilters do
10
+ describe ContextFilters::Filters::PriorityFilters do
11
11
 
12
12
  subject do
13
- ContextFilters::PriorityFilters.allocate
13
+ ContextFilters::Filters::PriorityFilters.allocate
14
14
  end
15
15
 
16
16
  describe "#initialize" do
@@ -34,8 +34,8 @@ describe ContextFilters::PriorityFilters do
34
34
  subject.send(:initialize, [:a, :b])
35
35
  subject.to_a.size.must_equal(2)
36
36
  subject.to_a.map(&:first).must_equal([:a, :b])
37
- subject.to_a[0][1].must_be_kind_of ContextFilters::Filters
38
- subject.to_a[1][1].must_be_kind_of ContextFilters::Filters
37
+ subject.to_a[0][1].must_be_kind_of ContextFilters::Filters::Filters
38
+ subject.to_a[1][1].must_be_kind_of ContextFilters::Filters::Filters
39
39
  end
40
40
 
41
41
  end #initialize
@@ -0,0 +1,57 @@
1
+ =begin
2
+ Copyright 2014 Michal Papis <mpapis@gmail.com>
3
+
4
+ See the file LICENSE for copying permission.
5
+ =end
6
+
7
+ require "test_helper"
8
+ require "context-filters/filters/store"
9
+
10
+ describe ContextFilters::Filters::Store do
11
+
12
+ subject do
13
+ Object.new.tap { |o| o.extend(ContextFilters::Filters::Store) }
14
+ end
15
+
16
+ it "adds empty filter" do
17
+ subject.store() { true }
18
+ subject.filters.size.must_equal 1
19
+ subject.filters.first.must_equal(nil)
20
+ end
21
+
22
+ it "adds options filter" do
23
+ subject.store(x: 2) { true }
24
+ subject.filters.size.must_equal 1
25
+ subject.filters.first.must_equal({x:2})
26
+ end
27
+
28
+ it "adds hash filter" do
29
+ subject.store({x: 3}) { true }
30
+ subject.filters.size.must_equal 1
31
+ subject.filters.first.must_equal({x:3})
32
+ end
33
+
34
+ it "adds nil filter" do
35
+ subject.store(nil) { true }
36
+ subject.filters.size.must_equal 1
37
+ subject.filters.first.must_equal(nil)
38
+ end
39
+
40
+ it "adds filter block" do
41
+ subject.store() { 4 }
42
+ subject.filters_store.size.must_equal 1
43
+ subject.filters_store[nil].size.must_equal 1
44
+ subject.filters_store[nil].first.call.must_equal(4)
45
+ end
46
+
47
+ it "is empty?" do
48
+ subject.filters_store.size.must_equal 0
49
+ subject.empty?.must_equal true
50
+ end
51
+
52
+ it "is not empty?" do
53
+ subject.store() { 4 }
54
+ subject.empty?.must_equal false
55
+ end
56
+
57
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: context-filters
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michal Papis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-17 00:00:00.000000000 Z
11
+ date: 2014-10-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: guard
@@ -103,17 +103,23 @@ extra_rdoc_files: []
103
103
  files:
104
104
  - lib/context-filters.rb
105
105
  - lib/context-filters/context.rb
106
- - lib/context-filters/filters.rb
107
- - lib/context-filters/global_context.rb
108
- - lib/context-filters/local_context.rb
109
- - lib/context-filters/priority_filters.rb
106
+ - lib/context-filters/context/global.rb
107
+ - lib/context-filters/context/global_context.rb
108
+ - lib/context-filters/context/global_filters.rb
109
+ - lib/context-filters/context/local.rb
110
+ - lib/context-filters/filters/filters.rb
111
+ - lib/context-filters/filters/priority_filters.rb
112
+ - lib/context-filters/filters/store.rb
110
113
  - lib/context-filters/version.rb
114
+ - test/context-filters/context/global_context_test.rb
115
+ - test/context-filters/context/global_filters_test.rb
116
+ - test/context-filters/context/global_test.rb
117
+ - test/context-filters/context/local_test.rb
111
118
  - test/context-filters/context_test.rb
112
119
  - test/context-filters/filter_test_subject.rb
113
- - test/context-filters/filters_test.rb
114
- - test/context-filters/global_context_test.rb
115
- - test/context-filters/local_context_test.rb
116
- - test/context-filters/priority_filters_test.rb
120
+ - test/context-filters/filters/filters_test.rb
121
+ - test/context-filters/filters/priority_filters_test.rb
122
+ - test/context-filters/filters/store_test.rb
117
123
  - test/test_helper.rb
118
124
  homepage: https://github.com/remote-exec/context-filters
119
125
  licenses:
@@ -141,10 +147,13 @@ specification_version: 4
141
147
  summary: Generic support for filters applied in context
142
148
  test_files:
143
149
  - test/test_helper.rb
144
- - test/context-filters/priority_filters_test.rb
145
- - test/context-filters/local_context_test.rb
146
150
  - test/context-filters/filter_test_subject.rb
147
- - test/context-filters/filters_test.rb
148
- - test/context-filters/global_context_test.rb
151
+ - test/context-filters/context/local_test.rb
152
+ - test/context-filters/context/global_test.rb
153
+ - test/context-filters/context/global_context_test.rb
154
+ - test/context-filters/context/global_filters_test.rb
149
155
  - test/context-filters/context_test.rb
156
+ - test/context-filters/filters/priority_filters_test.rb
157
+ - test/context-filters/filters/filters_test.rb
158
+ - test/context-filters/filters/store_test.rb
150
159
  has_rdoc:
@@ -1,90 +0,0 @@
1
- =begin
2
- Copyright 2014 Michal Papis <mpapis@gmail.com>
3
-
4
- See the file LICENSE for copying permission.
5
- =end
6
-
7
- require "context-filters/version"
8
-
9
- # Store and apply filters using blocks
10
- #
11
- # @example
12
- #
13
- # class FiltersTestSubject
14
- # attr_reader :value
15
- # def initialize(value)
16
- # @value = value
17
- # end
18
- # def change(&block)
19
- # @value = block.call(@value)
20
- # end
21
- # end
22
- # filters = ContextFilters::Filters.new
23
- # filters.store(:addition) {|value| value + 1 }
24
- # filters.store(:subtraction) {|value| value - 1 }
25
- # filters.filters # => [:addition, :subtraction]
26
- # object = FiltersTestSubject.new(3)
27
- # object.value => 3
28
- # filters.apply(object.method(:change), :addition)
29
- # object.value => 4
30
- # filters.apply(object.method(:change), :subtraction)
31
- # object.value => 3
32
-
33
- class ContextFilters::Filters
34
-
35
- # initialize the filters storage
36
- def initialize
37
- @filters = {}
38
- end
39
-
40
- # stores the block for given options, if the options have a block
41
- # already the new one is added to the list
42
- # @param options [Object] options for filtering blocks
43
- # @param block [Proc] block of code to add to the list of blocks
44
- # for this options
45
- def store(options = nil, &block)
46
- @filters[options] ||= []
47
- @filters[options] << block
48
- end
49
-
50
- # applies matching filters to the given target method, also uses
51
- # filters matching extra +:target => target+ when options is a Hash
52
- # @param target [Object] an object to run the method on
53
- # @param method [symbol] method name that takes a transformation
54
- # block as param
55
- # @param options [Object] a filter for selecting matching blocks
56
- def apply(target, method, options = nil)
57
- select_filters(target, options).each{|block| target.send(method, &block) }
58
- end
59
-
60
- # Select matching filters and filters including targets when
61
- # options is a +Hash+
62
- # @param target [Object] an object to run the method on
63
- # @param options [Object] a filter for selecting matching blocks
64
- def select_filters(target, options)
65
- found = @filters.fetch(options, [])
66
- if
67
- Hash === options || options.nil?
68
- then
69
- options ||={}
70
- options.merge!(:target => target)
71
- found +=
72
- # can not @filters.fetch(options, []) to allow filters provide custom ==()
73
- @filters.select do |filter_options, filters|
74
- options == filter_options
75
- end.map(&:last).flatten
76
- end
77
- found
78
- end
79
-
80
- # Array of already defined filters
81
- def filters
82
- @filters.keys
83
- end
84
-
85
- # @return [Boolean] true if there are any rules stored, false otherwise
86
- def empty?
87
- @filters.empty?
88
- end
89
-
90
- end
@@ -1,80 +0,0 @@
1
- =begin
2
- Copyright 2014 Michal Papis <mpapis@gmail.com>
3
-
4
- See the file LICENSE for copying permission.
5
- =end
6
-
7
- require "context-filters/priority_filters"
8
-
9
- # builds list of filters and provides dsl for building nested context
10
- # and allows evaluating filters on methods in the current context
11
- class ContextFilters::GlobalContext
12
-
13
- # @return [Array] the context stack
14
- # @api private
15
- attr_reader :context_stack
16
-
17
- # @return [PriorityFilters] shared list of filters
18
- # @api private
19
- attr_reader :priority_filters
20
-
21
- # initialize new GlobalContext, works in two modes:
22
- # 1. start totally new context, takes one param - array of priorities,
23
- # +nil+ to use one anonymous priority
24
- # 2. build sub context, params: global_filters_list, parents_context,
25
- # value to add to context
26
- #
27
- # @param priority_filters [Array,PriorityFilters] when PriorityFilters - uses it for priority_filters
28
- # otherwise - initializes new priority_filters with it
29
- # @param context_stack [Array] parents context_stack, duplicates to initialize own context_stack
30
- # @param options [Object] new context, ads it to context_stack
31
- #
32
- def initialize(priority_filters = nil, context_stack = [], options = nil)
33
- if ContextFilters::PriorityFilters === priority_filters
34
- then @priority_filters = priority_filters
35
- else @priority_filters = ContextFilters::PriorityFilters.new(priority_filters)
36
- end
37
- @context_stack = context_stack.dup + [options]
38
- end
39
-
40
- # defines new filter for given +priority+ and +options+
41
- #
42
- # @param priority [nil, Object] has to correspond to one of the initialized priorities
43
- # @param options [Object] the options to use for new filter
44
- # @param block [Proc] the transformation to use when the options match
45
- #
46
- def filter(priority, options = nil, &block)
47
- @priority_filters.store(priority, options, &block)
48
- end
49
-
50
- # starts new context
51
- # @param options [Object] options to start new context
52
- # @param block [Proc] code block that will enable filtering for the given +options+
53
- # @yield [GlobalContext] the new context
54
- def context(options, &block)
55
- self.class.new(@priority_filters, @context_stack, options).tap(&block)
56
- end
57
-
58
- # evaluates all matching filters for given context_stack, allows to do extra
59
- # work for +priority.nil?+ or on the end of the priorities,
60
- #
61
- # @param method [Proc] the method to evaluate with filters matching current context
62
- # @yield on first +priority.nil?+ or on the end when none
63
- def evaluate_filters(target, method)
64
- local_called = false
65
-
66
- @priority_filters.each do |priority, filters|
67
-
68
- @context_stack.each { |options| filters.apply(target, method, options) }
69
-
70
- if priority.nil? && block_given? && !local_called
71
- yield
72
- local_called = true
73
- end
74
-
75
- end
76
-
77
- yield if block_given? && !local_called
78
- end
79
-
80
- end
@@ -1,41 +0,0 @@
1
- =begin
2
- Copyright 2014 Michal Papis <mpapis@gmail.com>
3
-
4
- See the file LICENSE for copying permission.
5
- =end
6
-
7
- require "context-filters/version"
8
-
9
- # allow defining local filters and evaluating code in context of thems
10
- module ContextFilters::LocalContext
11
-
12
- # @return [Array<Proc>] list of blocks to evaluate
13
- # @api private
14
- def local_filters
15
- @local_filters ||= []
16
- end
17
-
18
- # temporarly adds +filter_block+ to the list of filters to run and
19
- # yields given block of code
20
- #
21
- # @param filter_block [Proc] a block of code to add to the list
22
- # @yield a block in which +local_filters+ temporarly includes
23
- # +filter_block+
24
- def local_filter(filter_block, &block)
25
- local_filters.push(filter_block)
26
- block.call
27
- ensure
28
- local_filters.pop
29
- nil
30
- end
31
-
32
- # iterates over +local_filters+ and applies them to the given +method+
33
- #
34
- # @param method [Proc] a method to call with each filter stored in
35
- # +local_filters+
36
- # @api private
37
- def evaluate_local_filters(target, method)
38
- local_filters.each { |block| target.send(method, &block) }
39
- end
40
-
41
- end
@@ -1,53 +0,0 @@
1
- =begin
2
- Copyright 2014 Michal Papis <mpapis@gmail.com>
3
-
4
- See the file LICENSE for copying permission.
5
- =end
6
-
7
- require "context-filters/filters"
8
-
9
- # list of +filters+ sorted by +priorities+
10
- class ContextFilters::PriorityFilters
11
-
12
- # @return [Array] list of priorities this object was initialized with
13
- attr_reader :priorities
14
-
15
- # initializes priorities and coresponding list of filters
16
- # @param priorities [Array|Object] a list of priorities to order filters
17
- def initialize(priorities = nil)
18
- @priorities = [priorities].flatten.freeze
19
- @filters_array = @priorities.product([ContextFilters::Filters.new])
20
- end
21
-
22
- # adds a priority filter
23
- #
24
- # @param priority [Object] anything that was part of +priorities+ array
25
- # @param options [Object] forwarded to Filters.store
26
- # @param block [Proc] forwarded to Filters.store
27
- # @raise [KeyError] when priority not matching priorities is used
28
- def store(priority, options = nil, &block)
29
- found = @filters_array.assoc(priority)
30
- raise KeyError if found.nil?
31
- found.last.store(options, &block)
32
- end
33
-
34
- # list of +filters+ sorted by +priorities+
35
- def to_a
36
- @filters_array
37
- end
38
-
39
- # iterate over +filters+ ordered by +priority+
40
- # @yield [priority,filters] the next filters from sorted array
41
- # @yieldparam priority [Object] the priority
42
- # @yieldparam filters [Filters] the filters for priority
43
- def each(&block)
44
- to_a.each(&block) unless empty?
45
- end
46
-
47
- # check if all of the filters are empty
48
- # return [Bolean] true if all filters are empty
49
- def empty?
50
- @filters_array.map(&:last).all?(&:empty?)
51
- end
52
-
53
- end
@@ -1,97 +0,0 @@
1
- =begin
2
- Copyright 2014 Michal Papis <mpapis@gmail.com>
3
-
4
- See the file LICENSE for copying permission.
5
- =end
6
-
7
- require "test_helper"
8
- require "context-filters/global_context"
9
- require "context-filters/filter_test_subject"
10
-
11
- describe ContextFilters::GlobalContext do
12
-
13
- subject do
14
- ContextFilters::GlobalContext.new
15
- end
16
-
17
- let(:filter_test_subject) do
18
- FilterTestSubject.new(3)
19
- end
20
-
21
- describe "#initialize" do
22
-
23
- it "sets up initial variables" do
24
- subject.priority_filters.must_be_kind_of ContextFilters::PriorityFilters
25
- subject.priority_filters.must_be_empty
26
- subject.context_stack.must_equal([nil])
27
- end
28
-
29
- end #initialize
30
-
31
- it "stores filters" do
32
- subject.priority_filters.expects(:store).with(nil, :a).once
33
- subject.filter(nil, :a) do true end
34
- end
35
-
36
- describe "#evaluate_filters" do
37
-
38
- it "does not apply filters when no filters" do
39
- subject.priority_filters.expects(:apply).never
40
- subject.evaluate_filters(filter_test_subject, :change)
41
- end
42
-
43
- it "does apply filters" do
44
- method = Proc.new{}
45
- subject.context_stack << :a
46
- subject.filter(nil, :b) { true }
47
- subject.priority_filters.to_a[0][1].expects(:apply).once.with(filter_test_subject, :change, nil)
48
- subject.priority_filters.to_a[0][1].expects(:apply).once.with(filter_test_subject, :change, :a)
49
- subject.evaluate_filters(filter_test_subject, :change)
50
- end
51
-
52
- it "does apply targeted filters in top context" do
53
- addition = Proc.new { |value| value+1 }
54
- multiplication = Proc.new { |value| value*3 }
55
- subject.filter(nil, {:target => filter_test_subject}, &addition)
56
- subject.filter(nil, {:target => nil}, &multiplication)
57
- subject.evaluate_filters(filter_test_subject, :change)
58
- filter_test_subject.value.must_equal(4)
59
- end
60
-
61
- it "does apply targeted filters in sub context" do
62
- addition = Proc.new { |value| value+1 }
63
- multiplication = Proc.new { |value| value*3 }
64
- subject.context_stack << { :a => 1 }
65
- subject.filter(nil, {:a => 1, :target => filter_test_subject}, &addition)
66
- subject.filter(nil, {:a => 1, :target => nil}, &multiplication)
67
- subject.evaluate_filters(filter_test_subject, :change)
68
- filter_test_subject.value.must_equal(4)
69
- end
70
-
71
- end #evaluate_command
72
-
73
- describe "#group" do
74
-
75
- it "nests" do
76
- subject.context(:a) do |test_a|
77
-
78
- test_a.must_be_kind_of ContextFilters::GlobalContext
79
- test_a.priority_filters.object_id.must_equal(subject.priority_filters.object_id)
80
- test_a.context_stack.object_id.wont_equal(subject.context_stack.object_id)
81
- test_a.context_stack.must_equal([nil, :a])
82
-
83
- test_a.context(:b) do |test_b|
84
- test_b.must_be_kind_of ContextFilters::GlobalContext
85
- test_b.priority_filters.object_id.must_equal(test_a.priority_filters.object_id)
86
- test_b.context_stack.object_id.wont_equal(test_a.context_stack.object_id)
87
- test_b.context_stack.must_equal([nil, :a, :b])
88
- end
89
-
90
- test_a.context_stack.must_equal([nil, :a])
91
- end
92
- subject.context_stack.must_equal([nil])
93
- end
94
-
95
- end #group
96
-
97
- end