arspy 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/README.rdoc +205 -0
  2. data/lib/arspy/operators.rb +34 -34
  3. metadata +2 -2
data/README.rdoc CHANGED
@@ -0,0 +1,205 @@
1
+ = ARSpy
2
+
3
+ A Rails console command line tool for exploring, browsing and inspecting
4
+ the structure, associations and data of ActiveRecord data models.
5
+
6
+ == Resources
7
+
8
+ Install
9
+
10
+ * sudo gem install arspy
11
+
12
+ Use
13
+
14
+ * require 'arspy'
15
+
16
+
17
+ == Description
18
+
19
+ ARSpy provides a number of functions for inspecting a Rails application's
20
+ ActiveRecord model. To use the gem all you need to to is the following:
21
+
22
+ sudo gem install arspy
23
+ ruby script/console
24
+ require 'arspy'
25
+
26
+ With ARSpy, you can view associations, fields and data related to tables and relations
27
+ in an easy-to-read format.
28
+
29
+ == Inspecting ActiveRecord Associations and Attributes (Fields)
30
+
31
+ === 'Listing fields' with the 'lf' command
32
+
33
+ Append the 'lf' command to an ActiveRecord object, class, or association method to
34
+ print the name, type and database variable type for each attribute.
35
+
36
+ User.lf
37
+ first_name :string (varchar(50))
38
+ last_name :string (varchar(50))
39
+ active :boolean (boolean)
40
+ age :age (int(11))
41
+
42
+
43
+ === 'Listing associations' with the 'la' command
44
+
45
+ Append the 'la' command to an ActiveRecord object, class or association method to
46
+ print the name, type, class and configuration information for each association.
47
+
48
+ User.la
49
+ blogs has_many (Blog)
50
+ comments has_many (Comment)
51
+ friendships has_many (Friendship)
52
+ friends has_many (User) {:through=>:friendships}
53
+ assets has_many (Asset) {:as=>:asset}
54
+
55
+ === Applying 'lf' and 'la' commands
56
+
57
+ The 'la' and 'lf' command can be used on any ActiveRecord object, class, association
58
+ or array of these.
59
+
60
+ u = User.find_by_last_name('Smith')
61
+ u.la
62
+ u.blogs.lf
63
+ u.blogs.title
64
+ u.blogs.la
65
+ u.blogs.comments.la
66
+ u.blogs.comments.user.lf
67
+ u.blogs.comments.user.pr(:first_name, :last_name) #see 'pr' command below
68
+
69
+
70
+ == Printing in Columns
71
+
72
+ === Printing arrays with the 'pr' command
73
+
74
+ Array data in the console is not so easy to read.
75
+
76
+ names
77
+ ["Peter Smith", "Sarah Johnson", "Randy Wade", "Alex Parsons", "Beth Silverton",
78
+ "Jenny Westmeyers", "Benjamin Grant", "Maria Stone"]
79
+
80
+ Use the 'pr' command to print in a column.
81
+
82
+ names.pr
83
+ Peter Smith
84
+ Sara Johnson
85
+ ...
86
+
87
+ === Print columns of object attributes with the 'pr' command
88
+
89
+ Arrays of ActiveRecord objects are even more difficult to read and analyze. Use
90
+ 'pr' command to print attributes (fields) in columns.
91
+
92
+ User.find(2).friends.pr :first_name, :last_name
93
+ Randy Wade
94
+ Benjamin Grant
95
+ Jenny Westmeyers
96
+ Maria Stone
97
+
98
+ === Printing expressions with 'pr' command
99
+
100
+ Pass an expression as one of the columns to the 'pr' command.
101
+
102
+ User.find(2).friends.pr '"#{last_name}, #{first_name}"', :age
103
+ Wade, Randy 25
104
+ Grant, Benjamin 28
105
+ Westmeyers, Jenny 24
106
+ Stone, Maria 33
107
+
108
+ Expressions using associations
109
+
110
+ User.find(2).friends.pr :first_name, :last_name, 'comments.count', 'blogs.count'
111
+ Randy Wade 23 3
112
+ Benjamin Grant 98 20
113
+ Jenny Westmeyers 213 2
114
+ Maria Stone 8 88
115
+
116
+
117
+ == Iterating Associations and Data
118
+
119
+ === Chaining associations to get data sets
120
+
121
+ Chain associations to get an array of the results. For example, the following will
122
+ collect all of the comment objects for all blogs written by User with ID=2.
123
+
124
+ User.find(2).blogs.comments
125
+ [#<Comment id: 21, user_id: 8, blog_id: 85, rating: 5, ...
126
+
127
+ Clean this up by further chainging to return an array of the 'comment' field
128
+ of each comment object and use 'pr' to print in a column.
129
+
130
+ User.find(2).blogs.comments.comment.pr
131
+ I agree with the blogger
132
+ I'm new to ActiveRecord. Is there anyway to...
133
+ How do you use polymorphic associations to...
134
+ ...
135
+
136
+ Note that chaining is accumulative. To limit the results set, use the 'wi' or 'wo'
137
+ commands.
138
+
139
+ == Limiting data sets
140
+
141
+ === Limiting with the 'with' command
142
+
143
+ The 'with' command is abbreviated to 'wi' in an expression. It's like saying only show
144
+ me the results with this condition OR this condition, etc.
145
+
146
+ Say we want to limit comments in the above example to only those written by Randy Wade
147
+ and Maria Stone. If their user ids are [5, 9], then we can write
148
+
149
+ User.find(2).blogs.comments.wi(:user_id=>[5, 9]).comments.pr
150
+
151
+ We could use ARSpy to look up the user ids.
152
+
153
+ User.find(2).blogs.comments.user.pr :first_name, :last_name, :id
154
+
155
+ Note in this example, the 'wi' command is acting on attributes of the object immediately
156
+ preceding it, namely, the Comment object.
157
+
158
+ === ORing and ANDing with the 'wi' command
159
+
160
+ The 'wi' command can take an unlimited number of parameters. Multiple parameters
161
+ works as an OR operation on the results. So the above example could have been written
162
+
163
+ User.find(2).blogs.comments.wi(:user_id=>5, :user_id=>9).comments.pr
164
+
165
+ with the same results.
166
+
167
+ To get an AND operation, chain the 'wi' command.
168
+
169
+ User.find(2).blogs.comments.wi(:blog_id=>6).wi(:user_id=>5).comments.pr
170
+
171
+ This example returns only comments for blog with ID 6 and user associated with
172
+ the comment with ID 5. On the other hand,
173
+
174
+ User.find(2).blogs.comments.wi(:blog_id=>6, :user_id=>5).comments.pr
175
+
176
+ returns all comments associated with blog id 6 OR user id 5.
177
+
178
+ === Parameters of the 'wi' command
179
+
180
+ The 'wi' command can take integers, strings and a hash of conditions.
181
+
182
+ Strings are expressions evaluated against the preceding object.
183
+
184
+ User.find(2).blogs.comments.wi('user.last_name.include?("Grant")').comment.pr
185
+
186
+ Integers are IDs for the object.
187
+
188
+ User.find(2).blogs.comments.wi(20,21,22).comment.pr
189
+
190
+ A hash of {attribute=>[values]}. The following displays comments belonging
191
+ to blogs with ids 6, 7 or 8.
192
+
193
+ User.find(2).blogs.comments.wi(:blog_id=>[6,7,8]).comments.pr
194
+
195
+
196
+ === Excluding with the 'wo' (without) command
197
+
198
+ The 'wo' command does the exact opposite of the 'wi' command, showing only those
199
+ results that do not meet the conditions passed in the parameters.
200
+
201
+
202
+ == Dependencies
203
+
204
+ * ActiveRecord
205
+ * ActiveSupport
@@ -2,31 +2,31 @@ module Arspy
2
2
  module Operators
3
3
  def self.list_associations(active_record_klass)
4
4
  counts = {}
5
- rows = active_record_klass.reflect_on_all_associations.map do |a|
6
- counts[a.macro] ||= 0
7
- counts[a.macro] += 1
8
- self.format_column_association(a)
5
+ rows = active_record_klass.reflect_on_all_associations.map do |assoc|
6
+ counts[assoc.macro] ||= 0
7
+ counts[assoc.macro] += 1
8
+ self.format_column_association(assoc)
9
9
  end
10
- rows.sort!{|a,b| a.first <=> b.first}
10
+ rows.sort!{|row1,row2| row1.first <=> row2.first}
11
11
  self.print_matrix(rows)
12
- "Total: #{counts.inject(0){|sum, c| sum+c.last}} (" + counts.map{|c| "#{c.last} #{c.first}" }.join(', ') + ")"
12
+ "Total: #{counts.inject(0){|sum, count| sum+count.last}} (" + counts.map{|count| "#{count.last} #{count.first}" }.join(', ') + ")"
13
13
  end
14
14
 
15
15
  def self.list_fields(active_record_klass)
16
- rows = active_record_klass.columns.map do |c|
17
- self.format_column_field(c)
16
+ rows = active_record_klass.columns.map do |column|
17
+ self.format_column_field(column)
18
18
  end
19
- rows.sort!{|a,b| a.first <=> b.first}
19
+ rows.sort!{|row1,row2| row1.first <=> row2.first}
20
20
  self.print_matrix(rows)
21
21
  "Total #{active_record_klass.columns.size} field#{active_record_klass.columns.size == 1 ? '' : 's'}"
22
22
  end
23
23
 
24
- def self.format_column_association(a)
25
- select_options = a.options.select{|k,v| [:through, :as, :polymorphic].include?(k)}
26
- [a.name.to_s, a.macro.to_s, "(#{a.options[:class_name] || a.name.to_s.singularize.camelize})", select_options.empty? ? '' : Hash[*select_options.flatten].inspect]
24
+ def self.format_column_association(assoc)
25
+ select_options = assoc.options.select{|k,v| [:through, :as, :polymorphic].include?(k)}
26
+ [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]
27
27
  end
28
- def self.format_column_field(f)
29
- [f.name.to_s, ":#{f.type}", "(#{f.sql_type})"]
28
+ def self.format_column_field(field)
29
+ [field.name.to_s, ":#{field.type}", "(#{field.sql_type})"]
30
30
  end
31
31
 
32
32
  def self.print_array(array, *args)
@@ -46,7 +46,7 @@ module Arspy
46
46
  end
47
47
 
48
48
  def self.print_object(object, *args)
49
- print_matrix([args.map{|a| object[a]}]) if args
49
+ print_matrix([args.map{|arg| object[arg]}]) if args
50
50
  puts(object.inspect) unless args
51
51
  nil
52
52
  end
@@ -56,7 +56,7 @@ module Arspy
56
56
  when String then obj.instance_eval(arg) rescue false
57
57
  when Integer then obj.id == arg
58
58
  when Hash
59
- arg.any?{|k,v| self.test_attribute(obj, k, (v.is_a?(Array) ? v : [v]) ) }
59
+ arg.any?{|key,val| self.test_attribute(obj, key, (val.is_a?(Array) ? val : [val]) ) }
60
60
  else
61
61
  false
62
62
  end
@@ -64,11 +64,11 @@ module Arspy
64
64
  end
65
65
  def self.with(array, *args)
66
66
  return array if (args.empty? || array.nil? || array.empty?)
67
- array.select{|o| o && self.test_object(o, args)}
67
+ array.select{|obj| obj && self.test_object(obj, args)}
68
68
  end
69
69
  def self.without(array, *args)
70
70
  return array if (args.empty? || array.nil? || array.empty?)
71
- array.select{|o| o && !self.test_object(o, args)}
71
+ array.select{|obj| obj && !self.test_object(obj, args)}
72
72
  end
73
73
  def self.enable_abbreviations; @@abbreviations_enabled = true; end
74
74
  def self.disable_abbreviations; @@abbreviations_enabled = false; end
@@ -110,35 +110,35 @@ module Arspy
110
110
  attrib_descriptors = attributes.map{|method_name| {:method_name=>method_name, :type=>:attribute, :abbr=>abbreviate_method_name(method_name)}}
111
111
  all_descriptors = assoc_descriptors + attrib_descriptors
112
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])
113
+ object.class.instance_variable_set('@arspy_abbreviations', Hash[*all_descriptors.map{|desc| [desc[:abbr], desc] }.flatten])
114
114
  end
115
115
  def self.remove_ambiguities(descriptors)
116
116
  list={}
117
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]
118
+ descriptors.each do |desc|
119
+ if list.include?(desc[:abbr])
120
+ if ambiguities[desc[:abbr]]
121
+ ambiguities[desc[:abbr]][:methods] << desc[:method_name]
122
122
  else
123
- ambiguities[d[:abbr]] = {:abbr=>d[:abbr], :methods=>[d[:method_name]]}
124
- ambiguities[d[:abbr]][:methods] << list[d[:abbr]][:method_name]
123
+ ambiguities[desc[:abbr]] = {:abbr=>desc[:abbr], :methods=>[desc[:method_name]]}
124
+ ambiguities[desc[:abbr]][:methods] << list[desc[:abbr]][:method_name]
125
125
  end
126
126
  else
127
- list[d[:abbr]] = d
127
+ list[desc[:abbr]] = desc
128
128
  end
129
129
  end
130
- descriptors.reject!{|d| ambiguities.map{|h| h.first}.include?(d[:abbr])}
130
+ descriptors.reject!{|desc| ambiguities.map{|h| h.first}.include?(desc[:abbr])}
131
131
  ambiguities
132
132
  end
133
133
  def self.abbreviate_method_name(method_name)
134
- splits = method_name.to_s.split('_')
134
+ words = method_name.to_s.split('_')
135
135
  abbr=[]
136
- if splits.first == ''
136
+ if words.first == ''
137
137
  abbr << '_'
138
138
  end
139
- splits.reject!{|s| s == ''}
140
- abbr += splits.map do |s|
141
- chars = s.split(//)
139
+ words.reject!{|word| word == ''}
140
+ abbr += words.map do |word|
141
+ chars = word.split(//)
142
142
  first = chars.shift
143
143
  [first, chars.map{|ch| ch =~ /[0-9]/ ? ch : nil}].compact.flatten.join('')
144
144
  end
@@ -156,8 +156,8 @@ module Arspy
156
156
  end
157
157
  def self.interpret_attribute_or_method(array, method_name, *args)
158
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)}
159
+ raise 'Hash not allowed as attribute conditionals' if args.any?{|arg| arg.is_a?(Hash)}
160
+ array.select{|obj| obj && self.test_attribute(obj, method_name, args)}
161
161
  end
162
162
  public
163
163
 
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 3
9
- version: 0.0.3
8
+ - 4
9
+ version: 0.0.4
10
10
  platform: ruby
11
11
  authors:
12
12
  - Jeff Patmon