arspy 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,8 +2,8 @@ module Arspy
2
2
  module ClassExtensions
3
3
  module ActiveRecord
4
4
  module Base
5
- def la; Arspy::Operators.la(self); end
6
- def lf; Arspy::Operators.lf(self); end
5
+ def la; Arspy::Operators.list_associations(self); end
6
+ def lf; Arspy::Operators.list_fields(self); end
7
7
  end
8
8
  end
9
9
  end
@@ -2,8 +2,8 @@ module Arspy
2
2
  module Delegators
3
3
  module ActiveRecordExtensions
4
4
  def pr(*args); Arspy::Operators.print_object(self, *args); end
5
- def la; Arspy::Operators.la(self.class); end
6
- def lf; Arspy::Operators.lf(self.class); end
5
+ def la; Arspy::Operators.list_associations(self.class); end
6
+ def lf; Arspy::Operators.list_fields(self.class); end
7
7
  end
8
8
  end
9
9
  end
@@ -14,10 +14,10 @@ module Arspy
14
14
  end
15
15
 
16
16
  def la
17
- Arspy::Operators.la(self.first.class) unless (self.emtpy? || !(self.first.is_a?(ActiveRecord::Base)))
17
+ Arspy::Operators.list_associations(self.first.class) unless (self.emtpy? || !(self.first.is_a?(ActiveRecord::Base)))
18
18
  end
19
19
  def lf
20
- Arspy::Operators.lf(self.first.class) unless (self.empty? || !(self.first.is_a?(ActiveRecord::Base)))
20
+ Arspy::Operators.list_fields(self.first.class) unless (self.empty? || !(self.first.is_a?(ActiveRecord::Base)))
21
21
  end
22
22
  def pr(*args)
23
23
  Arspy::Operators.print_array(self, *args)
@@ -15,11 +15,11 @@ module Arspy
15
15
  end
16
16
  def la
17
17
  load_target unless loaded?
18
- Arspy::Operators.la(@target.first.class) unless (@target.emtpy? || !(@target.first.is_a?(ActiveRecord::Base)))
18
+ Arspy::Operators.list_associations(@target.first.class) unless (@target.emtpy? || !(@target.first.is_a?(ActiveRecord::Base)))
19
19
  end
20
20
  def lf
21
21
  load_target unless loaded?
22
- Arspy::Operators.lf(@target.first.class) unless (@target.empty? || !(@target.first.is_a?(ActiveRecord::Base)))
22
+ Arspy::Operators.list_fields(@target.first.class) unless (@target.empty? || !(@target.first.is_a?(ActiveRecord::Base)))
23
23
  end
24
24
  def wi(*args)
25
25
  load_target unless loaded?
@@ -1,6 +1,6 @@
1
1
  module Arspy
2
2
  module Operators
3
- def self.la(active_record_klass)
3
+ def self.list_associations(active_record_klass)
4
4
  counts = {}
5
5
  rows = active_record_klass.reflect_on_all_associations.map do |a|
6
6
  counts[a.macro] ||= 0
@@ -12,7 +12,7 @@ module Arspy
12
12
  "Total: #{counts.inject(0){|sum, c| sum+c.last}} (" + counts.map{|c| "#{c.last} #{c.first}" }.join(', ') + ")"
13
13
  end
14
14
 
15
- def self.lf(active_record_klass)
15
+ def self.list_fields(active_record_klass)
16
16
  rows = active_record_klass.columns.map do |c|
17
17
  self.format_column_field(c)
18
18
  end
@@ -70,20 +70,96 @@ module Arspy
70
70
  return array if (args.empty? || array.nil? || array.empty?)
71
71
  array.select{|o| o && !self.test_object(o, args)}
72
72
  end
73
- def self.interpret(array, symbol, *args)
74
- return nil unless (array && symbol)
73
+ def self.enable_abbreviations; @@abbreviations_enabled = true; end
74
+ def self.disable_abbreviations; @@abbreviations_enabled = false; end
75
+ @@abbreviations_enabled = true
76
+ def self.interpret(array, method_name, *args)
77
+ return nil unless (array && method_name)
75
78
  return nil unless (array.is_a?(Array) && !array.empty? && array.first.is_a?(ActiveRecord::Base))
76
79
 
77
- if array.first.class.reflect_on_all_associations.detect{|a| a.name == symbol}
78
- array.map(&symbol).flatten
79
- elsif (array.first.attribute_names.include?(symbol.to_s) || array.first.respond_to?(symbol))
80
- return array.map(&symbol) if args.empty?
81
- raise 'Hash not allowed as attribute conditionals' if args.any?{|a| a.is_a?(Hash)}
82
- array.select{|o| o && self.test_attribute(o, symbol, args)}
83
- else
84
- nil
80
+ if array.first.class.reflect_on_all_associations.detect{|a| a.name == method_name}
81
+ return interpret_association(array, method_name, *args)
82
+ elsif (array.first.attribute_names.include?(method_name.to_s) || array.first.respond_to?(method_name))
83
+ return interpret_attribute_or_method(array, method_name, *args)
85
84
  end
85
+ return @@abbreviations_enabled ? interpret_abbreviation(array, method_name, *args) : nil
86
86
  end
87
+ private
88
+ def self.interpret_abbreviation(array, symbol, *args)
89
+ if (descriptor = resolve_abbreviation_for_attributes_and_associations(array.first, symbol))
90
+ if descriptor[:type] == :association
91
+ return interpret_association(array, descriptor[:method_name], *args)
92
+ else
93
+ return interpret_attribute_or_method(array, descriptor[:method_name], *args)
94
+ end
95
+ end
96
+ nil
97
+ end
98
+ def self.resolve_abbreviation_for_attributes_and_associations(object, method_name)
99
+ klass = object.class
100
+ setup_abbreviations(object) unless object.instance_variable_defined?('@arspy_abbreviations')
101
+ if (ambiguity = klass.instance_variable_get('@arspy_ambiguous_abbreviations')[method_name])
102
+ raise "Ambiguous abbreviation '#{ambiguity[:abbr]}' could be #{quote_and_join(ambiguity[:methods])}"
103
+ end
104
+ klass.instance_variable_get('@arspy_abbreviations')[method_name]
105
+ end
106
+ def self.setup_abbreviations(object)
107
+ associations = object.class.reflect_on_all_associations.map(&:name).map(&:to_sym)
108
+ attributes = object.attribute_names.map(&:to_sym)
109
+ assoc_descriptors = associations.map{|method_name| {:method_name=>method_name, :type=>:association, :abbr=>abbreviate_method_name(method_name)}}
110
+ attrib_descriptors = attributes.map{|method_name| {:method_name=>method_name, :type=>:attribute, :abbr=>abbreviate_method_name(method_name)}}
111
+ all_descriptors = assoc_descriptors + attrib_descriptors
112
+ object.class.instance_variable_set('@arspy_ambiguous_abbreviations', remove_ambiguities(all_descriptors))
113
+ object.class.instance_variable_set('@arspy_abbreviations', Hash[*all_descriptors.map{|d| [d[:abbr], d] }.flatten])
114
+ end
115
+ def self.remove_ambiguities(descriptors)
116
+ list={}
117
+ ambiguities = {}
118
+ descriptors.each do |d|
119
+ if list.include?(d[:abbr])
120
+ if ambiguities[d[:abbr]]
121
+ ambiguities[d[:abbr]][:methods] << d[:method_name]
122
+ else
123
+ ambiguities[d[:abbr]] = {:abbr=>d[:abbr], :methods=>[d[:method_name]]}
124
+ ambiguities[d[:abbr]][:methods] << list[d[:abbr]][:method_name]
125
+ end
126
+ else
127
+ list[d[:abbr]] = d
128
+ end
129
+ end
130
+ descriptors.reject!{|d| ambiguities.map{|h| h.first}.include?(d[:abbr])}
131
+ ambiguities
132
+ end
133
+ def self.abbreviate_method_name(method_name)
134
+ splits = method_name.to_s.split('_')
135
+ abbr=[]
136
+ if splits.first == ''
137
+ abbr << '_'
138
+ end
139
+ splits.reject!{|s| s == ''}
140
+ abbr += splits.map do |s|
141
+ chars = s.split(//)
142
+ first = chars.shift
143
+ [first, chars.map{|ch| ch =~ /[0-9]/ ? ch : nil}].compact.flatten.join('')
144
+ end
145
+
146
+ abbr << '_' if (method_name.to_s =~ /_$/)
147
+ abbr.join('').to_sym
148
+ end
149
+ def self.quote_and_join(array)
150
+ return "'#{array.first}'" if array.size == 1
151
+ last = array.pop
152
+ "'#{array.join("', '")}' or '#{last}'"
153
+ end
154
+ def self.interpret_association(array, method_name, *args)
155
+ array.map(&method_name).flatten
156
+ end
157
+ def self.interpret_attribute_or_method(array, method_name, *args)
158
+ return array.map(&method_name) if args.empty?
159
+ raise 'Hash not allowed as attribute conditionals' if args.any?{|a| a.is_a?(Hash)}
160
+ array.select{|o| o && self.test_attribute(o, method_name, args)}
161
+ end
162
+ public
87
163
 
88
164
  def self.test_attribute(obj, attr_sym, args)
89
165
  return false if (obj.nil? || attr_sym.nil? || args.empty?)
@@ -101,11 +177,6 @@ module Arspy
101
177
  end
102
178
  end
103
179
 
104
- def self.prepare_arguments(symbol, *args)
105
- return nil if args.empty?
106
- Hash[*args.map{|a| a.is_a?(Hash) ? a.map{|k,v| [k, v]} : [symbol, a]}.flatten]
107
- end
108
-
109
180
  @@column_padding = 2
110
181
  def self.print_matrix(matrix_array)
111
182
  return nil if matrix_array.empty?
data/spec/database.rb CHANGED
@@ -1,63 +1,80 @@
1
1
  require 'rubygems'
2
2
 
3
- gem 'activerecord', ENV['AR_VERSION'] ? "=#{ENV['AR_VERSION']}" : '>=2.1.0'
3
+ gem 'activerecord', ENV['AR_VERSION'] ? "=#{ENV['AR_VERSION']}" : '>=2.3.2'
4
4
  require 'active_record'
5
5
 
6
6
  ActiveRecord::Base.establish_connection({'adapter' => 'sqlite3', 'database' => ':memory:'})
7
7
  ActiveRecord::Base.logger = Logger.new("#{File.dirname(__FILE__)}/active_record.log")
8
8
  cx = ActiveRecord::Base.connection
9
9
 
10
- cx.create_table(:things, :force=>true) do |t|
11
-
10
+ cx.create_table(:people, :force=>true) do |t|
11
+ t.string :first_name
12
+ t.string :last_name
13
+ t.integer :age
14
+ t.boolean :active
12
15
  end
13
- cx.create_table(:one_manies, :force=>true) do |t|
14
16
 
17
+ class Person < ActiveRecord::Base
18
+ has_many :friendships
19
+ has_many :friends, :through=>:friendships
20
+ has_many :blogs
21
+ has_many :comments
22
+
23
+ def full_name; "#{first_name} #{last_name}"; end
15
24
  end
16
- cx.create_table(:many_manies, :force=>true) do |t|
17
25
 
26
+ cx.create_table(:friendships, :force=>true) do |t|
27
+ t.references :person
28
+ t.references :friend
29
+ t.integer :years_known
18
30
  end
19
- cx.create_table(:many_manies_things, :force=>true) do |t|
20
31
 
32
+ class Friendship < ActiveRecord::Base
33
+ belongs_to :person
34
+ belongs_to :friend, :class=>'Person'
21
35
  end
22
- cx.create_table(:manies_one, :force=>true) do |t|
23
36
 
37
+ cx.create_table(:blogs, :force=>true) do |t|
38
+ t.references :person
39
+ t.string :title
40
+ t.datetime :published_at
41
+ t.references :asset, :polymorphic=>true
24
42
  end
25
43
 
26
- #basic_associations
27
- connection.create_table(:companies, :force=>true) do |t|
28
- t.string :name
29
- t.string :status
30
- end
31
- connection.create_table(:contract_workers, :force=>true) do |t|
32
- t.references :company
33
- t.references :contractor
34
- t.string :status
44
+ class Blog < ActiveRecord::Base
45
+ belongs_to :person
46
+ belongs_to :asset, :polymorphic=>true
47
+ has_many :comments
35
48
  end
36
- connection.create_table(:licenses, :force=>true) do |t|
37
- t.references :company
38
- t.string :status
49
+
50
+ cx.create_table(:comments, :force=>true) do |t|
51
+ t.references :person
52
+ t.references :blog
53
+ t.string :content
39
54
  end
40
- connection.create_table(:contractors, :force=>true) do |t|
41
- t.string :name
42
- t.string :status
55
+
56
+ class Comment < ActiveRecord::Base
57
+ belongs_to :person
58
+ belongs_to :blog
43
59
  end
44
- connection.create_table(:employees, :force=>true) do |t|
45
- t.references :company
46
- t.string :name
47
- t.string :status
60
+
61
+ cx.create_table(:images, :force=>true) do |t|
62
+ t.string :caption
63
+ t.integer :size
48
64
  end
49
65
 
50
- #polymorphic_associations
51
- connection.create_table(:comments, :force=>true) do |t|
52
- t.references :document, :polymorphic=>true
53
- t.text :comment
54
- t.string :status
66
+ class Image < ActiveRecord::Base
67
+ has_one :blog, :as=>:asset
55
68
  end
56
- connection.create_table(:articles, :force=>true) do |t|
57
- t.string :name
58
- t.string :status
69
+
70
+ cx.create_table(:recordings, :force=>true) do |t|
71
+ t.string :title
72
+ t.integer :duration
59
73
  end
60
- connection.create_table(:images, :force=>true) do |t|
61
- t.string :name
62
- t.string :status
74
+
75
+ class Recording < ActiveRecord::Base
76
+ has_one :blog, :as=>:asset
63
77
  end
78
+
79
+
80
+
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 2
9
- version: 0.0.2
8
+ - 3
9
+ version: 0.0.3
10
10
  platform: ruby
11
11
  authors:
12
12
  - Jeff Patmon
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-04-03 00:00:00 -07:00
17
+ date: 2010-04-04 00:00:00 -07:00
18
18
  default_executable:
19
19
  dependencies: []
20
20