arspy 0.0.5 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'arspy/operators/selector/base'
|
2
|
+
require 'arspy/operators/selector/attribute_selector'
|
3
|
+
require 'arspy/operators/selector/range_selector'
|
4
|
+
require 'arspy/operators/selector/integer_selector'
|
5
|
+
require 'arspy/operators/selector/string_selector'
|
6
|
+
require 'arspy/operators/selector/unsupported_selector'
|
7
|
+
require 'arspy/operators/selector/hash_selector'
|
8
|
+
|
9
|
+
module Arspy
|
10
|
+
module Operators
|
11
|
+
|
12
|
+
module Selector
|
13
|
+
@@selector_classes = [
|
14
|
+
IntegerSelector,
|
15
|
+
RangeSelector,
|
16
|
+
StringSelector,
|
17
|
+
HashSelector,
|
18
|
+
UnsupportedSelector
|
19
|
+
]
|
20
|
+
|
21
|
+
def self.for(arg)
|
22
|
+
@@selector_classes.detect{|klass| klass.applies?(arg)}.new(arg)
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/arspy/operators.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
|
+
require 'arspy/operators/attribute_test'
|
2
|
+
require 'arspy/operators/selector'
|
3
|
+
require 'arspy/operators/interpreter'
|
4
|
+
|
1
5
|
module Arspy
|
2
6
|
module Operators
|
3
7
|
|
4
|
-
def self.list_associations(klass_or_object)
|
8
|
+
def self.list_associations(klass_or_object, *args)
|
5
9
|
active_record_klass = klass_or_object.is_a?(Class) ? klass_or_object : klass_or_object.class
|
6
10
|
return unless active_record_klass.ancestors.include?(ActiveRecord::Base)
|
7
11
|
counts = {}
|
@@ -11,23 +15,26 @@ module Arspy
|
|
11
15
|
self.format_column_association(assoc)
|
12
16
|
end
|
13
17
|
rows.sort!{|row1,row2| row1.first <=> row2.first}
|
18
|
+
return rows if args.include?(:data)
|
14
19
|
self.print_matrix(rows)
|
15
20
|
"Total: #{counts.inject(0){|sum, count| sum+count.last}} (" + counts.map{|count| "#{count.last} #{count.first}" }.join(', ') + ")"
|
16
21
|
end
|
17
22
|
|
18
|
-
def self.list_fields(klass_or_object)
|
23
|
+
def self.list_fields(klass_or_object, *args)
|
19
24
|
active_record_klass = klass_or_object.is_a?(Class) ? klass_or_object : klass_or_object.class
|
20
25
|
return unless active_record_klass.ancestors.include?(ActiveRecord::Base)
|
21
26
|
rows = active_record_klass.columns.map do |column|
|
22
27
|
self.format_column_field(column)
|
23
28
|
end
|
24
29
|
rows.sort!{|row1,row2| row1.first <=> row2.first}
|
30
|
+
return rows if args.include?(:data)
|
25
31
|
self.print_matrix(rows)
|
26
32
|
"Total #{active_record_klass.columns.size} field#{active_record_klass.columns.size == 1 ? '' : 's'}"
|
27
33
|
end
|
28
34
|
|
29
35
|
def self.awesome_print(klass_object_or_array, options={})
|
30
|
-
AwesomePrint.new(options).puts
|
36
|
+
#AwesomePrint.new(options).puts(klass_object_or_array)
|
37
|
+
ap(klass_object_or_array)
|
31
38
|
nil
|
32
39
|
end
|
33
40
|
|
@@ -36,13 +43,25 @@ module Arspy
|
|
36
43
|
[assoc.name.to_s, assoc.macro.to_s, "(#{assoc.options[:class_name] || assoc.name.to_s.singularize.camelize})", select_options.empty? ? '' : Hash[*select_options.flatten].inspect]
|
37
44
|
end
|
38
45
|
def self.format_column_field(field)
|
39
|
-
[field.name.to_s, ":#{field.type}",
|
46
|
+
[field.name.to_s, ":#{field.type}", format_db_type(field), format_db_type_modifiers(field)]
|
47
|
+
end
|
48
|
+
def self.format_db_type(field)
|
49
|
+
prec_scale = field.precision && field.scale ? "#{field.precision}:#{field.scale}" : ""
|
50
|
+
default = field.default ? " (#{field.default})" : ""
|
51
|
+
"#{field.sql_type}#{prec_scale}#{default}"
|
52
|
+
end
|
53
|
+
def self.format_db_type_modifiers(field)
|
54
|
+
modifiers = []
|
55
|
+
modifiers << 'PRIMARY' if field.primary
|
56
|
+
modifiers << 'NOT NULL' unless field.null
|
57
|
+
#modifiers << "LIMIT(#{field.limit})" if field.limit
|
58
|
+
modifiers.join(',')
|
40
59
|
end
|
41
60
|
|
42
61
|
def self.print_array(array, *args)
|
43
62
|
if args.empty?
|
44
63
|
case array.first
|
45
|
-
when ActiveRecord::Base then
|
64
|
+
when ActiveRecord::Base then ap(array)
|
46
65
|
else
|
47
66
|
array.each{|element| puts element}
|
48
67
|
end
|
@@ -64,7 +83,8 @@ module Arspy
|
|
64
83
|
|
65
84
|
def self.print_object(object, *args)
|
66
85
|
print_matrix([args.map{|arg| object[arg]}]) unless args.empty?
|
67
|
-
AwesomePrint.new.puts(object) if args.empty?
|
86
|
+
#AwesomePrint.new.puts(object) if args.empty?
|
87
|
+
ap(object) if args.empty?
|
68
88
|
nil
|
69
89
|
end
|
70
90
|
def self.test_object(obj, args)
|
@@ -79,121 +99,30 @@ module Arspy
|
|
79
99
|
end
|
80
100
|
end
|
81
101
|
end
|
102
|
+
# t.people.with(20..30)
|
103
|
+
# t.people.with(2,3,4)
|
104
|
+
# t.people.with(:name=>[/Ed/, /Jen/, 'Joe'])
|
105
|
+
# t.people.with(:age=>10..20)
|
106
|
+
# t.people.with('statistics.statistic_type.abbrevation'=>%w(GP SV% GAA))
|
82
107
|
def self.with(array, *args)
|
83
108
|
return array if (args.empty? || array.nil? || array.empty?)
|
84
|
-
array.select{|obj|
|
109
|
+
array.select{|obj|
|
110
|
+
obj && args.any?{|arg|
|
111
|
+
Selector.for(arg).select?(obj) }}
|
85
112
|
end
|
86
113
|
def self.without(array, *args)
|
87
114
|
return array if (args.empty? || array.nil? || array.empty?)
|
88
|
-
array.select{|obj| obj && !
|
115
|
+
array.select{|obj| obj && !args.any?{|arg| Selector.for(arg).select?(obj) }}
|
89
116
|
end
|
90
|
-
def self.enable_abbreviations; @@abbreviations_enabled = true; end
|
91
|
-
def self.disable_abbreviations; @@abbreviations_enabled = false; end
|
92
|
-
@@abbreviations_enabled = true
|
93
|
-
def self.interpret(array, method_name, *args)
|
94
|
-
return nil unless (array && method_name)
|
95
|
-
return nil unless (array.is_a?(Array) && !array.empty? && array.first.is_a?(ActiveRecord::Base))
|
96
117
|
|
97
|
-
|
98
|
-
|
99
|
-
elsif (array.first.attribute_names.include?(method_name.to_s) || array.first.respond_to?(method_name))
|
100
|
-
return interpret_attribute_or_method(array, method_name, *args)
|
101
|
-
end
|
102
|
-
return @@abbreviations_enabled ? interpret_abbreviation(array, method_name, *args) : nil
|
103
|
-
end
|
104
|
-
private
|
105
|
-
def self.interpret_abbreviation(array, symbol, *args)
|
106
|
-
if (descriptor = resolve_abbreviation_for_attributes_and_associations(array.first, symbol))
|
107
|
-
if descriptor[:type] == :association
|
108
|
-
return interpret_association(array, descriptor[:method_name], *args)
|
109
|
-
else
|
110
|
-
return interpret_attribute_or_method(array, descriptor[:method_name], *args)
|
111
|
-
end
|
112
|
-
end
|
113
|
-
nil
|
114
|
-
end
|
115
|
-
def self.resolve_abbreviation_for_attributes_and_associations(object, method_name)
|
116
|
-
klass = object.class
|
117
|
-
setup_abbreviations(object) unless object.instance_variable_defined?('@arspy_abbreviations')
|
118
|
-
if (ambiguity = klass.instance_variable_get('@arspy_ambiguous_abbreviations')[method_name])
|
119
|
-
raise "Ambiguous abbreviation '#{ambiguity[:abbr]}' could be #{quote_and_join(ambiguity[:methods])}"
|
120
|
-
end
|
121
|
-
klass.instance_variable_get('@arspy_abbreviations')[method_name]
|
122
|
-
end
|
123
|
-
def self.setup_abbreviations(object)
|
124
|
-
associations = object.class.reflect_on_all_associations.map(&:name).map(&:to_sym)
|
125
|
-
attributes = object.attribute_names.map(&:to_sym)
|
126
|
-
assoc_descriptors = associations.map{|method_name| {:method_name=>method_name, :type=>:association, :abbr=>abbreviate_method_name(method_name)}}
|
127
|
-
attrib_descriptors = attributes.map{|method_name| {:method_name=>method_name, :type=>:attribute, :abbr=>abbreviate_method_name(method_name)}}
|
128
|
-
all_descriptors = assoc_descriptors + attrib_descriptors
|
129
|
-
object.class.instance_variable_set('@arspy_ambiguous_abbreviations', remove_ambiguities(all_descriptors))
|
130
|
-
object.class.instance_variable_set('@arspy_abbreviations', Hash[*all_descriptors.map{|desc| [desc[:abbr], desc] }.flatten])
|
131
|
-
end
|
132
|
-
def self.remove_ambiguities(descriptors)
|
133
|
-
list={}
|
134
|
-
ambiguities = {}
|
135
|
-
descriptors.each do |desc|
|
136
|
-
if list.include?(desc[:abbr])
|
137
|
-
if ambiguities[desc[:abbr]]
|
138
|
-
ambiguities[desc[:abbr]][:methods] << desc[:method_name]
|
139
|
-
else
|
140
|
-
ambiguities[desc[:abbr]] = {:abbr=>desc[:abbr], :methods=>[desc[:method_name]]}
|
141
|
-
ambiguities[desc[:abbr]][:methods] << list[desc[:abbr]][:method_name]
|
142
|
-
end
|
143
|
-
else
|
144
|
-
list[desc[:abbr]] = desc
|
145
|
-
end
|
146
|
-
end
|
147
|
-
descriptors.reject!{|desc| ambiguities.map{|hash| hash.first}.include?(desc[:abbr])}
|
148
|
-
ambiguities
|
149
|
-
end
|
150
|
-
def self.abbreviate_method_name(method_name)
|
151
|
-
words = method_name.to_s.split('_')
|
152
|
-
abbr=[]
|
153
|
-
if words.first == ''
|
154
|
-
abbr << '_'
|
155
|
-
end
|
156
|
-
words.reject!{|word| word == ''}
|
157
|
-
abbr += words.map do |word|
|
158
|
-
chars = word.split(//)
|
159
|
-
first = chars.shift
|
160
|
-
[first, chars.map{|ch| ch =~ /[0-9]/ ? ch : nil}].compact.flatten.join('')
|
161
|
-
end
|
162
|
-
|
163
|
-
abbr << '_' if (method_name.to_s =~ /_$/)
|
164
|
-
abbr.join('').to_sym
|
165
|
-
end
|
166
|
-
def self.quote_and_join(array)
|
167
|
-
return "'#{array.first}'" if array.size == 1
|
168
|
-
last = array.pop
|
169
|
-
"'#{array.join("', '")}' or '#{last}'"
|
170
|
-
end
|
171
|
-
def self.interpret_association(array, method_name, *args)
|
172
|
-
array.map(&method_name).flatten
|
173
|
-
end
|
174
|
-
def self.interpret_attribute_or_method(array, method_name, *args)
|
175
|
-
return array.map(&method_name) if args.empty?
|
176
|
-
raise 'Hash not allowed as attribute conditionals' if args.any?{|arg| arg.is_a?(Hash)}
|
177
|
-
array.select{|obj| obj && self.test_attribute(obj, method_name, args)}
|
178
|
-
end
|
179
|
-
public
|
118
|
+
def self.enable_abbreviations; Interpreter.enable_abbreviations(true); end
|
119
|
+
def self.disable_abbreviations; Interpreter.enable_abbreviations(false); end
|
180
120
|
|
181
|
-
def self.
|
182
|
-
|
183
|
-
value = obj.__send__(attr_sym)
|
184
|
-
args.any? do |arg|
|
185
|
-
case arg
|
186
|
-
when String then (arg == value || (obj.instance_eval("#{attr_sym} #{arg}") rescue false))
|
187
|
-
when Regexp then arg.match(value)
|
188
|
-
when Range then arg.include?(value)
|
189
|
-
when Integer then (value.is_a?(ActiveRecord::Base) ? arg == value.id : arg == value) #TODO: what about value is association collection
|
190
|
-
when Float then arg == value
|
191
|
-
else
|
192
|
-
false
|
193
|
-
end
|
194
|
-
end
|
121
|
+
def self.interpret(array, method_name, *args)
|
122
|
+
Interpreter.for(array, method_name).interpret(*args)
|
195
123
|
end
|
196
124
|
|
125
|
+
|
197
126
|
@@column_padding = 2
|
198
127
|
def self.print_matrix(matrix_array)
|
199
128
|
return nil if matrix_array.empty?
|
@@ -2,10 +2,10 @@ module MetaProgramming
|
|
2
2
|
module Object
|
3
3
|
def self.included(base)
|
4
4
|
raise 'This module may only be included in class Object' unless base.name == 'Object'
|
5
|
-
base.extend(
|
5
|
+
base.extend(ClassMethods)
|
6
6
|
end
|
7
7
|
|
8
|
-
module
|
8
|
+
module ClassMethods
|
9
9
|
def metaclass
|
10
10
|
class << self; self; end
|
11
11
|
end
|