context-filters 0.10.0 → 0.11.0

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