arspy 0.0.5 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/README.rdoc +10 -0
  2. data/Rakefile +1 -1
  3. data/lib/arspy/class_extensions.rb +2 -2
  4. data/lib/arspy/delegators/active_record_extensions.rb +2 -2
  5. data/lib/arspy/delegators/array_extensions.rb +4 -4
  6. data/lib/arspy/delegators/association_collection_extensions.rb +4 -4
  7. data/lib/arspy/delegators/null_extensions.rb +2 -2
  8. data/lib/arspy/operators/abbreviations.rb +68 -0
  9. data/lib/arspy/operators/attribute_test/base.rb +11 -0
  10. data/lib/arspy/operators/attribute_test/float_test.rb +24 -0
  11. data/lib/arspy/operators/attribute_test/integer_test.rb +24 -0
  12. data/lib/arspy/operators/attribute_test/range_test.rb +24 -0
  13. data/lib/arspy/operators/attribute_test/regexp_test.rb +23 -0
  14. data/lib/arspy/operators/attribute_test/string_test.rb +23 -0
  15. data/lib/arspy/operators/attribute_test/unsupported_test.rb +17 -0
  16. data/lib/arspy/operators/attribute_test.rb +20 -0
  17. data/lib/arspy/operators/interpreter/abbreviated_association_interpreter.rb +22 -0
  18. data/lib/arspy/operators/interpreter/abbreviated_attribute_interpreter.rb +22 -0
  19. data/lib/arspy/operators/interpreter/association_interpreter.rb +18 -0
  20. data/lib/arspy/operators/interpreter/attribute_interpreter.rb +21 -0
  21. data/lib/arspy/operators/interpreter/base.rb +11 -0
  22. data/lib/arspy/operators/interpreter/method_interpreter.rb +14 -0
  23. data/lib/arspy/operators/interpreter/null_interpreter.rb +12 -0
  24. data/lib/arspy/operators/interpreter.rb +29 -0
  25. data/lib/arspy/operators/selector/attribute_selector.rb +33 -0
  26. data/lib/arspy/operators/selector/base.rb +12 -0
  27. data/lib/arspy/operators/selector/hash_selector.rb +30 -0
  28. data/lib/arspy/operators/selector/integer_selector.rb +17 -0
  29. data/lib/arspy/operators/selector/range_selector.rb +17 -0
  30. data/lib/arspy/operators/selector/string_selector.rb +14 -0
  31. data/lib/arspy/operators/selector/unsupported_selector.rb +17 -0
  32. data/lib/arspy/operators/selector.rb +28 -0
  33. data/lib/arspy/operators.rb +40 -111
  34. data/lib/meta_programming/object.rb +2 -2
  35. data/spec/active_record.log +4327 -0
  36. data/spec/database.rb +85 -32
  37. data/spec/list_association_spec.rb +62 -0
  38. data/spec/list_field_spec.rb +5 -0
  39. data/spec/spec_helper.rb +2 -0
  40. data/spec/with_command_spec.rb +106 -0
  41. 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
@@ -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 klass_object_or_array
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}", "(#{field.sql_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 AwesomePrint.new.puts(array)
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| obj && self.test_object(obj, args)}
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 && !self.test_object(obj, args)}
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
- if array.first.class.reflect_on_all_associations.detect{|a| a.name == method_name}
98
- return interpret_association(array, method_name, *args)
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.test_attribute(obj, attr_sym, args)
182
- return false if (obj.nil? || attr_sym.nil? || args.empty?)
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(ClassExtensions)
5
+ base.extend(ClassMethods)
6
6
  end
7
7
 
8
- module ClassExtensions
8
+ module ClassMethods
9
9
  def metaclass
10
10
  class << self; self; end
11
11
  end