arspy 0.0.5 → 0.0.7
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/README.rdoc +10 -0
- data/Rakefile +1 -1
- data/lib/arspy/class_extensions.rb +2 -2
- data/lib/arspy/delegators/active_record_extensions.rb +2 -2
- data/lib/arspy/delegators/array_extensions.rb +4 -4
- data/lib/arspy/delegators/association_collection_extensions.rb +4 -4
- data/lib/arspy/delegators/null_extensions.rb +2 -2
- data/lib/arspy/operators/abbreviations.rb +68 -0
- data/lib/arspy/operators/attribute_test/base.rb +11 -0
- data/lib/arspy/operators/attribute_test/float_test.rb +24 -0
- data/lib/arspy/operators/attribute_test/integer_test.rb +24 -0
- data/lib/arspy/operators/attribute_test/range_test.rb +24 -0
- data/lib/arspy/operators/attribute_test/regexp_test.rb +23 -0
- data/lib/arspy/operators/attribute_test/string_test.rb +23 -0
- data/lib/arspy/operators/attribute_test/unsupported_test.rb +17 -0
- data/lib/arspy/operators/attribute_test.rb +20 -0
- data/lib/arspy/operators/interpreter/abbreviated_association_interpreter.rb +22 -0
- data/lib/arspy/operators/interpreter/abbreviated_attribute_interpreter.rb +22 -0
- data/lib/arspy/operators/interpreter/association_interpreter.rb +18 -0
- data/lib/arspy/operators/interpreter/attribute_interpreter.rb +21 -0
- data/lib/arspy/operators/interpreter/base.rb +11 -0
- data/lib/arspy/operators/interpreter/method_interpreter.rb +14 -0
- data/lib/arspy/operators/interpreter/null_interpreter.rb +12 -0
- data/lib/arspy/operators/interpreter.rb +29 -0
- data/lib/arspy/operators/selector/attribute_selector.rb +33 -0
- data/lib/arspy/operators/selector/base.rb +12 -0
- data/lib/arspy/operators/selector/hash_selector.rb +30 -0
- data/lib/arspy/operators/selector/integer_selector.rb +17 -0
- data/lib/arspy/operators/selector/range_selector.rb +17 -0
- data/lib/arspy/operators/selector/string_selector.rb +14 -0
- data/lib/arspy/operators/selector/unsupported_selector.rb +17 -0
- data/lib/arspy/operators/selector.rb +28 -0
- data/lib/arspy/operators.rb +40 -111
- data/lib/meta_programming/object.rb +2 -2
- data/spec/active_record.log +4327 -0
- data/spec/database.rb +85 -32
- data/spec/list_association_spec.rb +62 -0
- data/spec/list_field_spec.rb +5 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/with_command_spec.rb +106 -0
- metadata +39 -7
data/README.rdoc
CHANGED
@@ -113,6 +113,15 @@ Expressions using associations
|
|
113
113
|
Jenny Westmeyers 213 2
|
114
114
|
Maria Stone 8 88
|
115
115
|
|
116
|
+
=== Printing objects and classes
|
117
|
+
|
118
|
+
ARSpy integrates 'awesome print' to print lists of objects and classes. Print objects or
|
119
|
+
classes with the 'pr' command, or explicitly print with the 'ap' command.
|
120
|
+
|
121
|
+
User.ap # => prints the object attributes and columns with awesome print
|
122
|
+
User.find(2).blogs.title.pr #=> prints the titles of all blogs
|
123
|
+
User.find(2).blogs.pr # => prints the object fields and data usign awesome print
|
124
|
+
|
116
125
|
|
117
126
|
== Iterating Associations and Data
|
118
127
|
|
@@ -203,3 +212,4 @@ results that do not meet the conditions passed in the parameters.
|
|
203
212
|
|
204
213
|
* ActiveRecord
|
205
214
|
* ActiveSupport
|
215
|
+
* Awesome Print
|
data/Rakefile
CHANGED
@@ -12,7 +12,7 @@ spec = Gem::Specification.new do |s|
|
|
12
12
|
s.description = 'Active Record Spy'
|
13
13
|
s.summary = 'Rails console command line tool for browsing and inspecting the structure, associations and data of an ActiveRecord data model.'
|
14
14
|
|
15
|
-
s.add_dependency('awesome_print', '>= 0.1.
|
15
|
+
s.add_dependency('awesome_print', '>= 0.1.4')
|
16
16
|
|
17
17
|
exclude_folders = '' # 'spec/rails/{doc,lib,log,nbproject,tmp,vendor,test}'
|
18
18
|
exclude_files = [] # FileList['**/*.log'] + FileList[exclude_folders+'/**/*'] + FileList[exclude_folders]
|
@@ -2,8 +2,8 @@ module Arspy
|
|
2
2
|
module ClassExtensions
|
3
3
|
module ActiveRecord
|
4
4
|
module Base
|
5
|
-
def la; Arspy::Operators.list_associations(self); end
|
6
|
-
def lf; Arspy::Operators.list_fields(self); end
|
5
|
+
def la(*args); Arspy::Operators.list_associations(self, *args); end
|
6
|
+
def lf(*args); Arspy::Operators.list_fields(self, *args); end
|
7
7
|
def pr; Arspy::Operators.awesome_print(self); end
|
8
8
|
def ap(opts={}); Arspy::Operators.awesome_print(self, opts); end
|
9
9
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
module Arspy
|
2
2
|
module Delegators
|
3
3
|
module ActiveRecordExtensions
|
4
|
-
def la; Arspy::Operators.list_associations(self.class); end
|
5
|
-
def lf; Arspy::Operators.list_fields(self.class); end
|
4
|
+
def la(*args); Arspy::Operators.list_associations(self.class, *args); end
|
5
|
+
def lf(*args); Arspy::Operators.list_fields(self.class, *args); end
|
6
6
|
def pr(*args); Arspy::Operators.print_object(self, *args); end
|
7
7
|
def ap(opts={}); Arspy::Operators.awesome_print(self, opts); end
|
8
8
|
end
|
@@ -13,11 +13,11 @@ module Arspy
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
def la
|
17
|
-
Arspy::Operators.list_associations(self.first) unless self.emtpy?
|
16
|
+
def la(*args)
|
17
|
+
Arspy::Operators.list_associations(self.first, *args) unless self.emtpy?
|
18
18
|
end
|
19
|
-
def lf
|
20
|
-
Arspy::Operators.list_fields(self.first) unless self.empty?
|
19
|
+
def lf(*args)
|
20
|
+
Arspy::Operators.list_fields(self.first, *args) unless self.empty?
|
21
21
|
end
|
22
22
|
def ap(opts={})
|
23
23
|
Arspy::Operators.awesome_print(self, opts={}) unless self.empty?
|
@@ -9,13 +9,13 @@ module Arspy
|
|
9
9
|
result
|
10
10
|
end
|
11
11
|
end
|
12
|
-
def la
|
12
|
+
def la(*args)
|
13
13
|
load_target unless loaded?
|
14
|
-
Arspy::Operators.list_associations(@target.first) unless @target.emtpy?
|
14
|
+
Arspy::Operators.list_associations(@target.first, *args) unless @target.emtpy?
|
15
15
|
end
|
16
|
-
def lf
|
16
|
+
def lf(*args)
|
17
17
|
load_target unless loaded?
|
18
|
-
Arspy::Operators.list_fields(@target.first) unless @target.empty?
|
18
|
+
Arspy::Operators.list_fields(@target.first, *args) unless @target.empty?
|
19
19
|
end
|
20
20
|
def pr(*args)
|
21
21
|
load_target unless loaded?
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Abbreviations
|
2
|
+
def self.included(base)
|
3
|
+
base.extend(ClassMethods)
|
4
|
+
end
|
5
|
+
|
6
|
+
def resolve_abbreviation_for_attributes_and_associations!(object, method_name)
|
7
|
+
self.class.resolve_abbreviation_for_attributes_and_associations!(object, method_name)
|
8
|
+
end
|
9
|
+
module ClassMethods
|
10
|
+
def resolve_abbreviation_for_attributes_and_associations!(object, method_name)
|
11
|
+
klass = object.class
|
12
|
+
setup_abbreviations(object) unless object.instance_variable_defined?('@arspy_abbreviations')
|
13
|
+
if (ambiguity = klass.instance_variable_get('@arspy_ambiguous_abbreviations')[method_name])
|
14
|
+
raise "Ambiguous abbreviation '#{ambiguity[:abbr]}' could be #{quote_and_join(ambiguity[:methods])}"
|
15
|
+
end
|
16
|
+
klass.instance_variable_get('@arspy_abbreviations')[method_name]
|
17
|
+
end
|
18
|
+
|
19
|
+
def setup_abbreviations(object)
|
20
|
+
associations = object.class.reflect_on_all_associations.map(&:name).map(&:to_sym)
|
21
|
+
attributes = object.attribute_names.map(&:to_sym)
|
22
|
+
assoc_descriptors = associations.map{|method_name| {:method_name=>method_name, :type=>:association, :abbr=>abbreviate_method_name(method_name)}}
|
23
|
+
attrib_descriptors = attributes.map{|method_name| {:method_name=>method_name, :type=>:attribute, :abbr=>abbreviate_method_name(method_name)}}
|
24
|
+
all_descriptors = assoc_descriptors + attrib_descriptors
|
25
|
+
object.class.instance_variable_set('@arspy_ambiguous_abbreviations', remove_ambiguities(all_descriptors))
|
26
|
+
object.class.instance_variable_set('@arspy_abbreviations', Hash[*all_descriptors.map{|desc| [desc[:abbr], desc] }.flatten])
|
27
|
+
end
|
28
|
+
def remove_ambiguities(descriptors)
|
29
|
+
list={}
|
30
|
+
ambiguities = {}
|
31
|
+
descriptors.each do |desc|
|
32
|
+
if list.include?(desc[:abbr])
|
33
|
+
if ambiguities[desc[:abbr]]
|
34
|
+
ambiguities[desc[:abbr]][:methods] << desc[:method_name]
|
35
|
+
else
|
36
|
+
ambiguities[desc[:abbr]] = {:abbr=>desc[:abbr], :methods=>[desc[:method_name]]}
|
37
|
+
ambiguities[desc[:abbr]][:methods] << list[desc[:abbr]][:method_name]
|
38
|
+
end
|
39
|
+
else
|
40
|
+
list[desc[:abbr]] = desc
|
41
|
+
end
|
42
|
+
end
|
43
|
+
descriptors.reject!{|desc| ambiguities.map{|hash| hash.first}.include?(desc[:abbr])}
|
44
|
+
ambiguities
|
45
|
+
end
|
46
|
+
def abbreviate_method_name(method_name)
|
47
|
+
words = method_name.to_s.split('_')
|
48
|
+
abbr=[]
|
49
|
+
if words.first == ''
|
50
|
+
abbr << '_'
|
51
|
+
end
|
52
|
+
words.reject!{|word| word == ''}
|
53
|
+
abbr += words.map do |word|
|
54
|
+
chars = word.split(//)
|
55
|
+
first = chars.shift
|
56
|
+
[first, chars.map{|ch| ch =~ /[0-9]/ ? ch : nil}].compact.flatten.join('')
|
57
|
+
end
|
58
|
+
|
59
|
+
abbr << '_' if (method_name.to_s =~ /_$/)
|
60
|
+
abbr.join('').to_sym
|
61
|
+
end
|
62
|
+
def quote_and_join(array)
|
63
|
+
return "'#{array.first}'" if array.size == 1
|
64
|
+
last = array.pop
|
65
|
+
"'#{array.join("', '")}' or '#{last}'"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Arspy
|
2
|
+
module Operators
|
3
|
+
module AttributeTest
|
4
|
+
|
5
|
+
|
6
|
+
class FloatTest < Base
|
7
|
+
|
8
|
+
def self.applies?(param)
|
9
|
+
param.is_a? Float
|
10
|
+
end
|
11
|
+
|
12
|
+
def match?(value_or_object)
|
13
|
+
case value_or_object
|
14
|
+
when ActiveRecord::Base
|
15
|
+
false
|
16
|
+
else
|
17
|
+
value_or_object.to_f == @param rescue nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Arspy
|
2
|
+
module Operators
|
3
|
+
module AttributeTest
|
4
|
+
|
5
|
+
|
6
|
+
class IntegerTest < Base
|
7
|
+
|
8
|
+
def self.applies?(param)
|
9
|
+
param.is_a? Integer
|
10
|
+
end
|
11
|
+
|
12
|
+
def match?(value_or_object)
|
13
|
+
case value_or_object
|
14
|
+
when ActiveRecord::Base
|
15
|
+
value_or_object.id == @param
|
16
|
+
else
|
17
|
+
value_or_object.to_i == @param rescue nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Arspy
|
2
|
+
module Operators
|
3
|
+
module AttributeTest
|
4
|
+
|
5
|
+
|
6
|
+
class RangeTest < Base
|
7
|
+
|
8
|
+
def self.applies?(param)
|
9
|
+
param.is_a? Range
|
10
|
+
end
|
11
|
+
|
12
|
+
def match?(value_or_object)
|
13
|
+
case value_or_object
|
14
|
+
when ActiveRecord::Base
|
15
|
+
@param.include?(value_or_object.id)
|
16
|
+
else
|
17
|
+
@param.include?(value_or_object.to_i)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Arspy
|
2
|
+
module Operators
|
3
|
+
module AttributeTest
|
4
|
+
|
5
|
+
class RegexpTest < Base
|
6
|
+
def self.applies?(param)
|
7
|
+
param.is_a? Regexp
|
8
|
+
end
|
9
|
+
|
10
|
+
def match?(value_or_object)
|
11
|
+
case value_or_object
|
12
|
+
when ActiveRecord::Base
|
13
|
+
raise "Test for '#{@param}' on object '#{value_or_object.class.name}' not supported."
|
14
|
+
else
|
15
|
+
value_or_object =~ @param
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Arspy
|
2
|
+
module Operators
|
3
|
+
module AttributeTest
|
4
|
+
|
5
|
+
class StringTest < Base
|
6
|
+
|
7
|
+
def self.applies?(param)
|
8
|
+
param.is_a? String
|
9
|
+
end
|
10
|
+
|
11
|
+
def match?(value_or_object)
|
12
|
+
case value_or_object
|
13
|
+
when ActiveRecord::Base
|
14
|
+
value_or_object.instance_eval{ value_or_object }
|
15
|
+
else
|
16
|
+
value_or_object.to_s == @param rescue nil
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Arspy
|
2
|
+
module Operators
|
3
|
+
module AttributeTest
|
4
|
+
class UnsupportedTest < Base
|
5
|
+
|
6
|
+
def self.applies?(param)
|
7
|
+
true
|
8
|
+
end
|
9
|
+
|
10
|
+
def match?(object)
|
11
|
+
raise "#{@param.class.name} '#{@param.inspect}' not supported."
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'arspy/operators/attribute_test/base'
|
2
|
+
require 'arspy/operators/attribute_test/integer_test'
|
3
|
+
require 'arspy/operators/attribute_test/range_test'
|
4
|
+
require 'arspy/operators/attribute_test/regexp_test'
|
5
|
+
require 'arspy/operators/attribute_test/string_test'
|
6
|
+
require 'arspy/operators/attribute_test/unsupported_test'
|
7
|
+
|
8
|
+
module Arspy
|
9
|
+
module Operators
|
10
|
+
module AttributeTest
|
11
|
+
@@attribute_test_classes = [
|
12
|
+
IntegerTest, RangeTest, StringTest, RegexpTest, UnsupportedTest
|
13
|
+
]
|
14
|
+
|
15
|
+
def self.for(param)
|
16
|
+
@@attribute_test_classes.detect{|klass| klass.applies?(param)}.new(param)
|
17
|
+
end
|
18
|
+
|
19
|
+
end end
|
20
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'arspy/operators/abbreviations'
|
2
|
+
module Arspy
|
3
|
+
module Operators
|
4
|
+
module Interpreter
|
5
|
+
class AbbreviatedAssociationInterpreter < AssociationInterpreter
|
6
|
+
include Abbreviations
|
7
|
+
|
8
|
+
def self.applies?(array, method_name)
|
9
|
+
descriptor = resolve_abbreviation_for_attributes_and_associations!(array.first, method_name)
|
10
|
+
descriptor && descriptor[:type] == :association
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(array, method_name)
|
14
|
+
descriptor = resolve_abbreviation_for_attributes_and_associations!(array.first, method_name)
|
15
|
+
super(array, descriptor[:method_name])
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'arspy/operators/abbreviations'
|
2
|
+
|
3
|
+
module Arspy
|
4
|
+
module Operators
|
5
|
+
module Interpreter
|
6
|
+
class AbbreviatedAttributeInterpreter < AttributeInterpreter
|
7
|
+
include Abbreviations
|
8
|
+
|
9
|
+
def self.applies?(array, method_name)
|
10
|
+
descriptor = resolve_abbreviation_for_attributes_and_associations!(array.first, method_name)
|
11
|
+
descriptor && descriptor[:type] == :attribute
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(array, method_name)
|
15
|
+
descriptor = resolve_abbreviation_for_attributes_and_associations!(array.first, method_name)
|
16
|
+
super(array, descriptor[:method_name])
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Arspy
|
2
|
+
module Operators
|
3
|
+
module Interpreter
|
4
|
+
|
5
|
+
class AssociationInterpreter < Base
|
6
|
+
|
7
|
+
def self.applies?(array, method_name)
|
8
|
+
array.first.class.reflect_on_all_associations.detect{|a| a.name == method_name}
|
9
|
+
end
|
10
|
+
|
11
|
+
def interpret(*args)
|
12
|
+
@array.map(&@method_name).flatten
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Arspy
|
2
|
+
module Operators
|
3
|
+
module Interpreter
|
4
|
+
class AttributeInterpreter < Base
|
5
|
+
|
6
|
+
def self.applies?(array, method_name)
|
7
|
+
array.first.attribute_names.include?(method_name.to_s)
|
8
|
+
end
|
9
|
+
|
10
|
+
def interpret(*args)
|
11
|
+
return @array.map(&@method_name) if args.empty?
|
12
|
+
raise 'Hash not supported as attribute conditionals' if args.any?{|arg| arg.is_a?(Hash)}
|
13
|
+
selector = Selector.for({@method_name => args})
|
14
|
+
@array.select{|obj| obj && selector.select?(obj)}
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Arspy
|
2
|
+
module Operators
|
3
|
+
module Interpreter
|
4
|
+
|
5
|
+
class MethodInterpreter < AttributeInterpreter
|
6
|
+
def self.applies?(array, method_name)
|
7
|
+
array.first.respond_to?(method_name) && array.first.method(method_name).arity == 0
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
require 'arspy/operators/interpreter/base'
|
3
|
+
require 'arspy/operators/interpreter/association_interpreter'
|
4
|
+
require 'arspy/operators/interpreter/attribute_interpreter'
|
5
|
+
require 'arspy/operators/interpreter/method_interpreter'
|
6
|
+
require 'arspy/operators/interpreter/abbreviated_association_interpreter'
|
7
|
+
require 'arspy/operators/interpreter/abbreviated_attribute_interpreter'
|
8
|
+
require 'arspy/operators/interpreter/null_interpreter'
|
9
|
+
|
10
|
+
module Arspy
|
11
|
+
module Operators
|
12
|
+
module Interpreter
|
13
|
+
@@interpreter_classes = [
|
14
|
+
AssociationInterpreter, AttributeInterpreter,
|
15
|
+
MethodInterpreter, AbbreviatedAssociationInterpreter,
|
16
|
+
AbbreviatedAttributeInterpreter,
|
17
|
+
NullInterpreter
|
18
|
+
]
|
19
|
+
|
20
|
+
def self.for(array, method_name)
|
21
|
+
return NullInterpreter.new(array, method_name) unless (array && method_name && array.is_a?(Array) && !array.empty? && array.first.is_a?(ActiveRecord::Base))
|
22
|
+
@@interpreter_classes.detect{|klass| klass.applies?(array, method_name)}.new(array, method_name)
|
23
|
+
end
|
24
|
+
|
25
|
+
@@abbreviations_enabled = true
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Arspy
|
2
|
+
module Operators
|
3
|
+
module Selector
|
4
|
+
|
5
|
+
class AttributeSelector < Base
|
6
|
+
def self.applies?(key_value)
|
7
|
+
key_value.first.is_a? Symbol
|
8
|
+
end
|
9
|
+
def initialize(key_value)
|
10
|
+
super
|
11
|
+
@attribute = key_value.first.to_sym
|
12
|
+
@test_values = key_value.last.is_a?(Array) ? key_value.last : [key_value.last]
|
13
|
+
end
|
14
|
+
|
15
|
+
def select?(obj)
|
16
|
+
raise "Attribute '#{@attribute}' not found for #{obj.class.name}" unless obj.attribute_names.include?(@attribute.to_s)
|
17
|
+
response = obj.__send__ @attribute
|
18
|
+
return nil unless response
|
19
|
+
raise "Attributes resulting in arrays not supported" if response.is_a?(Array)
|
20
|
+
response = [response] unless response.is_a?(Array)
|
21
|
+
response.any?{|value_or_object| attribute_tests.any?{|test| test.match?(value_or_object)}}
|
22
|
+
end
|
23
|
+
|
24
|
+
def attribute_tests
|
25
|
+
@attribute_tests ||= @test_values.map do |param|
|
26
|
+
AttributeTest.for(param)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Arspy
|
2
|
+
module Operators
|
3
|
+
module Selector
|
4
|
+
|
5
|
+
class HashSelector < Base
|
6
|
+
@@hash_selector_classes = [
|
7
|
+
Selector::AttributeSelector,
|
8
|
+
Selector::UnsupportedSelector
|
9
|
+
]
|
10
|
+
def self.applies?(arg)
|
11
|
+
arg.is_a? Hash
|
12
|
+
end
|
13
|
+
|
14
|
+
def select?(obj)
|
15
|
+
selectors.any?{|selector| selector.select?(obj) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def selectors
|
19
|
+
@selectors ||= @argument.map do |key_value|
|
20
|
+
hash_selector_class_for(key_value).new(key_value)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
def hash_selector_class_for(key_value)
|
24
|
+
@@hash_selector_classes.detect{|klass| klass.applies?(key_value) }
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Arspy
|
2
|
+
module Operators
|
3
|
+
module Selector
|
4
|
+
class UnsupportedSelector < Base
|
5
|
+
def self.applies?(arg)
|
6
|
+
true
|
7
|
+
end
|
8
|
+
def initialize(arg)
|
9
|
+
raise "#{arg.inspect} not supported."
|
10
|
+
end
|
11
|
+
def select?(obj)
|
12
|
+
nil
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|