arspy 0.0.2 → 0.0.3

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