wagn 1.14.7 → 1.14.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/JASMINE_RAILS_TEST.md +16 -0
  3. data/VERSION +1 -1
  4. data/db/bootstrap/card_actions.yml +501 -480
  5. data/db/bootstrap/card_acts.yml +1 -1
  6. data/db/bootstrap/card_changes.yml +1815 -1752
  7. data/db/bootstrap/cards.yml +1500 -1443
  8. data/db/migrate/20141121172918_rename_card_migration_table.rb +8 -1
  9. data/lib/card/chunk.rb +0 -1
  10. data/lib/card/content.rb +1 -1
  11. data/lib/card/format.rb +6 -4
  12. data/lib/card/generators/card_migration/card_migration_generator.rb +1 -2
  13. data/lib/card/loader.rb +4 -0
  14. data/lib/card/set.rb +21 -7
  15. data/lib/card/set_pattern.rb +38 -5
  16. data/lib/wagn.rb +3 -3
  17. data/lib/wagn/core_migration.rb +1 -15
  18. data/lib/wagn/generators/wagn/templates/Rakefile +0 -1
  19. data/lib/wagn/log.rb +297 -94
  20. data/lib/wagn/migration.rb +53 -24
  21. data/lib/wagn/tasks/wagn.rake +17 -19
  22. data/mod/01_core/set/all/collection.rb +1 -1
  23. data/mod/01_core/set/all/content.rb +5 -2
  24. data/mod/01_core/set/all/fetch.rb +35 -35
  25. data/mod/01_core/set/all/trash.rb +3 -3
  26. data/mod/01_core/set/all/type.rb +7 -4
  27. data/mod/01_core/spec/set/all/tracked_attributes_spec.rb +1 -1
  28. data/mod/01_core/spec/set/all/trash_spec.rb +19 -0
  29. data/mod/02_basic_types/spec/set/type/pointer_spec.rb +13 -3
  30. data/mod/03_machines/set/type/coffee_script.rb +5 -3
  31. data/mod/03_machines/set/type/css.rb +4 -2
  32. data/mod/03_machines/set/type/java_script.rb +5 -4
  33. data/mod/04_settings/set/right/style.rb +3 -2
  34. data/mod/05_email/format/email_text_format.rb +4 -0
  35. data/mod/05_email/set/all/email_text.rb +1 -2
  36. data/mod/05_email/set/right/bcc.rb +8 -4
  37. data/mod/05_email/set/type/email_template.rb +20 -20
  38. data/mod/05_standard/set/all/attach.rb +0 -1
  39. data/mod/05_standard/set/type/basic.rb +3 -1
  40. data/mod/05_standard/set/type/html.rb +7 -5
  41. data/mod/05_standard/spec/set/type/email_template_spec.rb +166 -99
  42. data/public/assets/ace/ext-searchbox.js +409 -0
  43. data/spec/lib/card/set_pattern_spec.rb +18 -1
  44. data/spec/lib/wagn/log_spec.rb +217 -56
  45. data/test/fixtures/card_actions.yml +945 -924
  46. data/test/fixtures/card_acts.yml +101 -101
  47. data/test/fixtures/card_changes.yml +3764 -3701
  48. data/test/fixtures/cards.yml +2012 -1955
  49. metadata +4 -2
@@ -1,7 +1,14 @@
1
1
  class RenameCardMigrationTable < ActiveRecord::Migration
2
2
  def self.up
3
- rename_table :schema_migrations_cards, :schema_migrations_core_cards
3
+ if ActiveRecord::Base.connection.table_exists? :schema_migrations_cards
4
+ rename_table :schema_migrations_cards, :schema_migrations_core_cards
5
+ else
6
+ create_table "schema_migrations_core_cards", :id => false, :force => true do |t|
7
+ t.string "version", :null => false
8
+ end
9
+ end
4
10
  end
11
+
5
12
  def self.down
6
13
  rename_table :schema_migrations_core_cards, :schema_migrations_cards
7
14
  end
@@ -47,7 +47,6 @@ class Card
47
47
  register_list :default, [ :URI, :HostURI, :EmailURI, :EscapedLiteral, :Include, :Link ]
48
48
  register_list :references, [ :EscapedLiteral, :Include, :Link ]
49
49
  register_list :inclusion_only, [ :Include ]
50
- register_list :inclusion_and_link, [ :Include, :Link ]
51
50
 
52
51
  class Abstract
53
52
  class_attribute :config
@@ -26,7 +26,7 @@ class Card
26
26
  end
27
27
 
28
28
  def chunk_list
29
- @opts[:chunk_list] || card.chunk_list
29
+ @opts[:chunk_list] || @format.chunk_list
30
30
  end
31
31
 
32
32
  def to_s
@@ -26,11 +26,13 @@ class Card
26
26
  end
27
27
 
28
28
  def format_class_name format
29
- f = format.to_s
30
- f = @@aliases[ f ] || f
31
- "#{ f.camelize }Format"
29
+ format = format.to_s
30
+ format = '' if format == 'base'
31
+ format = @@aliases[ format ] if @@aliases[ format ]
32
+ "#{ format.camelize }Format"
32
33
  end
33
34
 
35
+
34
36
 
35
37
  def extract_class_vars view, opts
36
38
  return unless opts.present?
@@ -183,7 +185,7 @@ class Card
183
185
  @current_view = view = ok_view canonicalize_view( view ), args
184
186
  args = default_render_args view, args
185
187
  with_inclusion_mode view do
186
- Wagn.with_logging :view, view, :context=>card.name, :details=>args do
188
+ Wagn.with_logging :view, :message=>view, :context=>card.name, :details=>args do
187
189
  send "_view_#{ view }", args
188
190
  end
189
191
  end
@@ -8,8 +8,7 @@ class CardMigrationGenerator < ActiveRecord::Generators::Base
8
8
  desc: "Create card migration for wagn core"
9
9
 
10
10
  def create_migration_file
11
- migration_type = options['core'] ? :core_cards : :deck_cards
12
- root = Wagn::Migration.paths(migration_type).first
11
+ root = options['core'] ? Wagn::CoreMigration.paths.first : Wagn::Migration.paths.first
13
12
  set_local_assigns!
14
13
  migration_template @migration_template, File.join( root, "#{file_name}.rb")
15
14
  end
@@ -10,6 +10,10 @@ class Card
10
10
  load_set_patterns
11
11
  load_formats
12
12
  load_sets
13
+
14
+ if Wagn.config.performance_logger
15
+ Wagn::Log::Performance.load_config Wagn.config.performance_logger
16
+ end
13
17
  end
14
18
 
15
19
  def load_chunks
@@ -107,10 +107,22 @@ class Card
107
107
 
108
108
  end
109
109
 
110
- def format format=nil, &block
111
- klass = Card::Format.format_class_name format # format class name, eg. HtmlFormat
112
- mod = const_get_or_set klass do # called on current set module, eg Card::Set::Type::Pointer
113
- m = Module.new # yielding set format module, eg Card::Set::Type::Pointer::HtmlFormat
110
+
111
+ def format *format_names, &block
112
+ if format_names.empty?
113
+ format_names = [:base]
114
+ elsif format_names.first == :all
115
+ format_names = Card::Format.registered.reject {|f| Card::Format.aliases[f]}
116
+ end
117
+ format_names.each do |f|
118
+ define_on_format f, &block
119
+ end
120
+ end
121
+
122
+ def define_on_format format_name=:base, &block
123
+ klass = Card::Format.format_class_name format_name # format class name, eg. HtmlFormat
124
+ mod = const_get_or_set klass do # called on current set module, eg Card::Set::Type::Pointer
125
+ m = Module.new # yielding set format module, eg Card::Set::Type::Pointer::HtmlFormat
114
126
  register_set_format Card.const_get(klass), m
115
127
  m.extend Card::Set::Format
116
128
  m
@@ -136,7 +148,7 @@ class Card
136
148
 
137
149
  define_method event do
138
150
  run_callbacks event do
139
- Wagn.with_logging :event, event, :context=>self.name, :details=>opts do
151
+ Wagn.with_logging :event, :message=>event, :context=>self.name, :details=>opts do
140
152
  send final_method
141
153
  end
142
154
  end
@@ -200,9 +212,11 @@ class Card
200
212
  # FIXME - this does not properly handle anchorless sets
201
213
  # There are special hacks for *all, but others (like *rstar) will not be found by
202
214
  # include_set_modules, which will look for Card::Set::Rstar, not Card::Set::Rstar::Blah
203
-
215
+ # This issue appears to be addressed by making the entries, in modules arrays.
216
+ # If yes remove this comment.
217
+
204
218
  to_file = "#{Wagn.paths['tmp/set'].first}/#{set_pattern}/#{seq}-#{anchors.join '-'}.rb"
205
- anchor_modules = anchors.map { |a| "module #{a.camelize};" }.join
219
+ anchor_modules = anchors.map { |a| "module #{a.camelize};" }.join # use explicit '', not $,
206
220
  file_content = <<EOF
207
221
  # -*- encoding : utf-8 -*-
208
222
  class Card; module Set; module #{set_pattern.camelize}; #{anchor_modules}
@@ -1,4 +1,5 @@
1
1
  class Card
2
+
2
3
  class SetPattern
3
4
 
4
5
  class << self
@@ -38,11 +39,11 @@ class Card
38
39
  def pattern_applies? card
39
40
  junction_only? ? card.cardname.junction? : true
40
41
  end
41
-
42
+
42
43
  def anchor_parts_count
43
44
  @anchor_parts_count ||= ( anchorless? ? 0 : 1 )
44
45
  end
45
-
46
+
46
47
  def write_tmp_file pattern_code, from_file, seq
47
48
  to_file = "#{Wagn.paths['tmp/set_pattern'].first}/#{seq}-#{pattern_code}.rb"
48
49
  klass = "Card::#{pattern_code.camelize}Set"
@@ -91,12 +92,16 @@ EOF
91
92
  end
92
93
  end
93
94
 
95
+ def lookup_module_list modules_hash
96
+ module_key && modules_hash[ module_key ]
97
+ end
98
+
94
99
  def module_list
95
- module_key and Card::Set.modules[ :nonbase ][ module_key ]
100
+ lookup_module_list Card::Set.modules[ :nonbase ]
96
101
  end
97
102
 
98
103
  def format_module_list klass
99
- module_key and hash = Card::Set.modules[ :nonbase_format ][ klass ] and hash[ module_key ]
104
+ hash = Card::Set.modules[ :nonbase_format ][ klass ] and lookup_module_list hash
100
105
  end
101
106
 
102
107
  def anchor_codenames
@@ -130,6 +135,34 @@ EOF
130
135
  [ @anchor_id, self.class.pattern_code ].map( &:to_s ) * '+'
131
136
  end
132
137
  end
133
-
138
+ end
139
+
140
+ class TypeSet < SetPattern
141
+ def initialize card
142
+ super
143
+ @inherit_card = card unless module_key
144
+ end
145
+
146
+ def lookup_inherited_key
147
+ return unless @inherit_card
148
+ card, @inherit_card = @inherit_card, nil
149
+
150
+ default_rule = card.rule_card(:default) and
151
+ type_code = default_rule.type_code and
152
+ #default_rule.cardname.size > 2 and
153
+ #default_rule.left.right.codename == self.class.pattern_code
154
+ mod_key = "Type::#{type_code.to_s.camelize}" and
155
+ ( Card::Set.modules[:nonbase_format].values +
156
+ [Card::Set.modules[:nonbase]] ).any?{|hash| hash[mod_key]} and
157
+ mod_key
158
+ end
159
+
160
+ def inherited_key
161
+ (defined? @inherited_key) ? @inherited_key : @inherited_key = lookup_inherited_key
162
+ end
163
+
164
+ def lookup_module_list modules_hash
165
+ module_key ? modules_hash[ module_key ] : inherited_key && modules_hash[ inherited_key ]
166
+ end
134
167
  end
135
168
  end
@@ -24,9 +24,9 @@ module Wagn
24
24
  WAGN_GEM_ROOT
25
25
  end
26
26
 
27
- def with_logging method, message, opts, &block
28
- if (pl_config=Wagn.config.performance_logger) && pl_config[:methods] && pl_config[:methods].include?(method)
29
- Wagn::Log::Performance.with_timer(method, message, opts) do
27
+ def with_logging method, opts, &block
28
+ if Wagn::Log::Performance.enabled_method? method
29
+ Wagn::Log::Performance.with_timer(method, opts) do
30
30
  block.call
31
31
  end
32
32
  else
@@ -1,19 +1,5 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
 
3
3
  class Wagn::CoreMigration < Wagn::Migration
4
- def migration_paths
5
- Wagn::Migration.paths :core_cards
6
- end
7
-
8
- def schema_mode
9
- Wagn::Migration.schema_mode :core_cards
10
- end
11
-
12
- def import_json filename
13
- Wagn.config.action_mailer.perform_deliveries = false
14
- raw_json = File.read( data_path filename )
15
- json = JSON.parse raw_json
16
- Card.merge_list json["card"]["value"], :output_file=>File.join(data_path,"unmerged_#{ filename }")
17
- #fixme - output file should not be in gem!
18
- end
4
+ @type = :core_cards
19
5
  end
@@ -3,6 +3,5 @@
3
3
  # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
4
4
 
5
5
  require File.expand_path('../config/application', __FILE__)
6
- require 'jasmine'
7
6
 
8
7
  <%= app_const %>.load_tasks
@@ -1,14 +1,16 @@
1
1
  require 'csv'
2
2
 
3
+
3
4
  class Wagn::Log
4
5
 
5
6
  class Request
7
+
6
8
  def self.path
7
9
  path = (Wagn.paths['request_log'] && Wagn.paths['request_log'].first) || File.dirname(Wagn.paths['log'].first)
8
10
  filename = "#{Date.today}_#{Rails.env}.csv"
9
11
  File.join path, filename
10
12
  end
11
-
13
+
12
14
  def self.write_log_entry controller
13
15
  return if controller.env["REQUEST_URI"] =~ %r{^/files?/}
14
16
 
@@ -34,24 +36,230 @@ class Wagn::Log
34
36
  end
35
37
 
36
38
  end
37
-
39
+
38
40
 
39
41
  class Performance
42
+ # To enable logging add a performance_logger hash to your configuration and change the log_level to :wagn
43
+ # config options
44
+ #
45
+ # Example:
46
+ # config.performance_logger = {
47
+ # :min_time => 100, # show only method calls that are slower than 100ms
48
+ # :max_depth => 3, # show nested method calls only up to depth 3
49
+ # :details=> true # show method arguments and sql
50
+ # :methods => [:event, :search, :fetch, :view], # choose methods to log
51
+ # }
52
+ #
53
+ # If you give :methods a hash you can log arbitrary methods. The syntax is as follows:
54
+ # class => method type => method name => log options
55
+ #
56
+ # Example:
57
+ # Card => {
58
+ # :instance => [ :fetch, :search ],
59
+ # :singleton => { :fetch => { :title => 'Card.fetch' } },
60
+ # :all => {
61
+ # :fetch => {
62
+ # :message => 2 # use second argument passed to fetch
63
+ # :details => :to_s # use return value of to_s in method context
64
+ # :title => proc { |method_context| method_context.name }
65
+ # },
66
+ # },
67
+ # },
68
+ #
69
+ # class, method type and log options are optional.
70
+ # Default values are 'Card', ':all' and { :title => method name, :message => first argument, :details=> remaining arguments }.
71
+ # For example [:fetch] is equivalent to Card => { :all => { :fetch => { :message=>1, :details=>1..-1 } }
72
+
73
+ DEFAULT_CLASS = Card
74
+ DEFAULT_METHOD_TYPE = :all
75
+ DEFAULT_METHOD_OPTIONS = {
76
+ :title => :method_name,
77
+ :message => 1,
78
+ :details => 1..-1,
79
+ :context => nil
80
+ }
81
+
82
+ SPECIAL_METHODS = [:search, :view, :event] # these methods have already a Wagn.with_logging block
83
+ # we don't have to monkey patch them, only turn the logging on with adding the symbol to the methods hash
84
+
85
+
86
+
40
87
  TAB_SIZE = 3
41
88
  @@log = []
42
89
  @@context_entries = []
43
90
  @@active_entries = []
44
91
  @@current_level = 0
45
-
46
- def self.the_log
47
- @@the_log
92
+
93
+
94
+ class << self
95
+ def load_config args
96
+ @details = args[:details] || false
97
+ @max_depth = args[:max_depth] || false
98
+ @min_time = args[:min_time] || false
99
+ @enabled_methods = ::Set.new
100
+ prepare_methods_for_logging args[:methods] if args[:methods]
101
+ end
102
+
103
+ def start args={}
104
+ @@current_level = 0
105
+ @@log = []
106
+ @@context_entries = []
107
+ @@active_entries = []
108
+ @@first_entry = new_entry(args)
109
+ end
110
+
111
+ def stop
112
+ while (entry = @@context_entries.pop) do
113
+ finish_entry entry
114
+ end
115
+ if @@first_entry
116
+ @@first_entry.save_duration
117
+ finish_entry @@first_entry
118
+ end
119
+ print_log
120
+ end
121
+
122
+
123
+ def with_timer method, args, &block
124
+ if args[:context]
125
+
126
+ # if the previous context was created by an entry on the same level
127
+ # then finish the current context if it's a different context
128
+ if @@context_entries.last && @@current_level == @@context_entries.last.level+1 &&
129
+ args[:context] != @@context_entries.last.context
130
+ finish_entry @@context_entries.pop
131
+ end
132
+
133
+ # start new context if it's different from the parent context
134
+ if @@context_entries.empty? || args[:context] != @@context_entries.last.context
135
+ @@context_entries << new_entry( :title=>'process', :message=>args[:context], :context=>args[:context] )
136
+ end
137
+ end
138
+
139
+ timer = new_entry args.merge(:method=>method )
140
+ begin
141
+ result = block.call
142
+ ensure
143
+ timer.save_duration
144
+ finish_entry timer
145
+
146
+ # finish all deeper nested contexts
147
+ while @@context_entries.last && @@context_entries.last.level >= @@current_level
148
+ finish_entry @@context_entries.pop
149
+ end
150
+ # we don't know whether the next entry will belong to the same context or will start a new one
151
+ # so we save the time
152
+ @@context_entries.last.save_duration if @@context_entries.last
153
+ end
154
+ result
155
+ end
156
+
157
+
158
+ def enable_method method_name
159
+ @enabled_methods ||= ::Set.new
160
+ @enabled_methods << method_name
161
+ end
162
+
163
+ def enabled_method? method_name
164
+ @enabled_methods && @enabled_methods.include?(method_name)
165
+ end
166
+
167
+ private
168
+
169
+ def print_log
170
+ @@log.each do |entry|
171
+ Rails.logger.wagn entry.to_s! if entry.valid
172
+ end
173
+ end
174
+
175
+ def new_entry args
176
+ args.delete(:details) unless @details
177
+ level = @@current_level
178
+
179
+ last_entry = @@active_entries.last
180
+ parent = if last_entry
181
+ last_entry.level == level ? last_entry.parent : last_entry
182
+ end
183
+
184
+ @@log << Wagn::Log::Performance::Entry.new(parent, level, args )
185
+ @@current_level += 1
186
+ @@active_entries << @@log.last
187
+
188
+ @@log.last
189
+ end
190
+
191
+ def finish_entry entry
192
+ if (@max_depth && entry.level > @max_depth) || (@min_time && entry.duration < @min_time)
193
+ entry.delete
194
+ end
195
+ @@active_entries.pop
196
+ @@current_level -= 1
197
+ end
198
+
199
+ def prepare_methods_for_logging args
200
+ classes = hashify_and_verify_keys( args, DEFAULT_CLASS ) do |key|
201
+ key.kind_of?(Class) || key.kind_of?(Module)
202
+ end
203
+
204
+ classes.each do |klass, method_types|
205
+ klass.extend BigBrother # add watch methods
206
+
207
+ method_types = hashify_and_verify_keys( method_types, DEFAULT_METHOD_TYPE ) do |key|
208
+ [:all, :instance, :singleton].include? key
209
+ end
210
+
211
+ method_types.each do |method_type, methods|
212
+ methods = hashify_and_verify_keys methods
213
+ methods.each do |method_name, options|
214
+ klass.watch_method method_name, method_type, DEFAULT_METHOD_OPTIONS.merge(options)
215
+ end
216
+ end
217
+
218
+ end
219
+ end
220
+
221
+
222
+ def hashify_and_verify_keys args, default_key=nil
223
+ if default_key
224
+ case args
225
+ when Symbol
226
+ { default_key => [ args ] }
227
+ when Array
228
+ { default_key => args }
229
+ when Hash
230
+ if block_given?
231
+ args.keys.select{ |key| !(yield(key)) }.each do |key|
232
+ args[default_key] = { key => args[key] }
233
+ args.delete key
234
+ end
235
+ end
236
+ args
237
+ end
238
+ else
239
+ case args
240
+ when Symbol
241
+ { args => {} }
242
+ when Array
243
+ args.inject({}) do |h, key|
244
+ h[key] = {}
245
+ h
246
+ end
247
+ else
248
+ args
249
+ end
250
+ end
251
+ end
252
+
48
253
  end
254
+
255
+
49
256
  class Entry
50
257
  attr_accessor :level, :valid, :context, :parent, :children_cnt, :duration
51
-
258
+
52
259
  def initialize( parent, level, args )
53
260
  @start = Time.new
54
- @message = "#{ args[:method] }: #{ args[:message] }"
261
+ @message = "#{ args[:title] || args[:method] || '' }"
262
+ @message += ": #{ args[:message] }" if args[:message]
55
263
  @details = args[:details]
56
264
  @context = args[:context]
57
265
  @level = level
@@ -59,7 +267,7 @@ class Wagn::Log
59
267
  @valid = true
60
268
  @parent = parent
61
269
  @children_cnt = 0
62
- if @parent
270
+ if @parent
63
271
  @parent.add_children
64
272
  #@sibling_nr = @parent.children_cnt
65
273
  end
@@ -68,19 +276,19 @@ class Wagn::Log
68
276
  def add_children
69
277
  @children_cnt += 1
70
278
  end
71
-
279
+
72
280
  def delete_children
73
281
  @children_cnt -= 1
74
282
  end
75
-
283
+
76
284
  def has_younger_siblings?
77
285
  @parent && @parent.children_cnt > 0 #@sibling_nr
78
286
  end
79
-
287
+
80
288
  def save_duration
81
289
  @duration = (Time.now - @start) * 1000
82
290
  end
83
-
291
+
84
292
  def delete
85
293
  @valid = false
86
294
  @parent.delete_children if @parent
@@ -90,11 +298,11 @@ class Wagn::Log
90
298
  # deletes the children counts in order to print the tree;
91
299
  # must be called in the right order
92
300
  #
93
- # More robuts but more expensive approach: use @sibling_nr instead of counting @children_cnt down,
94
- # but @sibling_nr has to be updated for all siblings of an entry if the entry gets deleted due to
301
+ # More robuts but more expensive approach: use @sibling_nr instead of counting @children_cnt down,
302
+ # but @sibling_nr has to be updated for all siblings of an entry if the entry gets deleted due to
95
303
  # min_time or max_depth restrictions in the config, so we have to save all children relations for that
96
304
  def to_s!
97
- @to_s ||= begin
305
+ @to_s ||= begin
98
306
  msg = indent
99
307
  msg += if @duration
100
308
  "(%d.2ms) #{@message}" % @duration
@@ -108,8 +316,8 @@ class Wagn::Log
108
316
  msg
109
317
  end
110
318
  end
111
-
112
- private
319
+
320
+ private
113
321
 
114
322
  def indent link=true
115
323
  @indent ||= begin
@@ -119,12 +327,12 @@ class Wagn::Log
119
327
  res = ' '
120
328
  res += (1..level-1).inject('') do |msg, index|
121
329
  if younger_siblings[index]
122
- msg << '|' + ' ' * (TAB_SIZE-1)
330
+ msg << '|' + ' ' * (TAB_SIZE-1)
123
331
  else
124
332
  msg << ' ' * TAB_SIZE
125
333
  end
126
334
  end
127
-
335
+
128
336
  res += link ? '|--' : ' '
129
337
  end
130
338
  end
@@ -139,99 +347,94 @@ class Wagn::Log
139
347
  end
140
348
  res.reverse
141
349
  end
142
-
350
+
143
351
  end
352
+
353
+
354
+ module BigBrother
144
355
 
356
+ def watch_method method_name, method_type=:all, options={}
357
+ Wagn::Log::Performance.enable_method method_name
145
358
 
146
- class << self
147
- def start args={}
148
- @@current_level = 0
149
- @@log = []
150
- @@context_entries = []
151
- @@active_entries = []
152
- @@first_entry = new_entry(args)
153
- end
154
-
155
- def stop
156
- while (entry = @@context_entries.pop) do
157
- finish_entry entry
359
+ if !SPECIAL_METHODS.include? method_name
360
+ if method_type == :all || method_type == :singleton
361
+ add_singleton_logging method_name, options
362
+ end
363
+ if method_type == :all || method_type == :instance
364
+ add_instance_logging method_name, options
365
+ end
158
366
  end
159
- if @@first_entry
160
- @@first_entry.save_duration
161
- finish_entry @@first_entry
367
+ end
368
+
369
+ def watch_instance_method *names
370
+ names.each do |name|
371
+ watch_method name, :instance
162
372
  end
163
- print_log
164
373
  end
165
-
166
- def with_timer method, message, args, &block
167
- if args[:context]
168
-
169
- # if the previous context was created by an entry on the same level
170
- # the finish the context if it's a different context
171
- if @@context_entries.last && @@current_level == @@context_entries.last.level+1 &&
172
- args[:context] != @@context_entries.last.context
173
- finish_entry @@context_entries.pop
174
- end
175
-
176
- # start new context if it's different from the parent context
177
- if @@context_entries.empty? || args[:context] != @@context_entries.last.context
178
- @@context_entries << new_entry( :method=>'process', :message=>args[:context], :context=>args[:context] )
179
- end
374
+
375
+ def watch_singleton_method *names
376
+ names.each do |name|
377
+ watch_method name, :singleton
180
378
  end
379
+ end
181
380
 
182
- timer = new_entry args.merge(:method=>method, :message=>message)
183
- begin
184
- result = block.call
185
- ensure
186
- timer.save_duration
187
- finish_entry timer
381
+ def watch_all_instance_methods
382
+ watch_instance_method *instance_methods
383
+ end
188
384
 
189
- # finish all deeper nested contexts
190
- while @@context_entries.last && @@context_entries.last.level >= @@current_level
191
- finish_entry @@context_entries.pop
192
- end
193
- # we don't know whether the next entry will belong to the same context or will start a new one
194
- # so we save the time
195
- @@context_entries.last.save_duration if @@context_entries.last
385
+ def watch_all_singleton_methods
386
+ fragile_methods = [:default_scope, :default_scopes, :default_scopes=] # if I touch these methods ActiveRecord breaks
387
+ watch_singleton_method *(singleton_methods - fragile_methods)
388
+ end
389
+
390
+ def watch_all_methods
391
+ watch_all_instance_methods
392
+ watch_all_singleton_methods
393
+ end
394
+
395
+ private
396
+
397
+ def add_singleton_logging method_name, options
398
+ return unless singleton_class.method_defined? method_name
399
+ m = method(method_name)
400
+ add_logging method_name, :define_singleton_method, options do |bind_object, args, &block|
401
+ m.call(*args, &block)
196
402
  end
197
- result
198
403
  end
199
404
 
200
- private
201
-
202
- def print_log
203
- @@log.each do |entry|
204
- Rails.logger.wagn entry.to_s! if entry.valid
405
+ def add_instance_logging method_name, options
406
+ return unless method_defined? method_name
407
+ m = instance_method(method_name)
408
+ add_logging method_name, :define_method, options do |bind_object, args, &block|
409
+ m.bind(bind_object).(*args, &block)
205
410
  end
206
411
  end
207
-
208
- def new_entry args
209
- args.delete(:details) unless Wagn.config.performance_logger[:details]
210
- level = @@current_level
211
-
212
- last_entry = @@active_entries.last
213
- parent = if last_entry
214
- last_entry.level == level ? last_entry.parent : last_entry
412
+
413
+ def add_logging method_name, define_method, options, &bind_block
414
+ send(define_method, method_name) do |*args, &block|
415
+ log_args = {}
416
+ options.each do |key,value|
417
+ log_args[key] = case value
418
+ when Integer then args[value-1]
419
+ when Range then args[value]
420
+ when Symbol then eval(value.to_s)
421
+ when Proc then value.call(self)
422
+ else value
423
+ end
424
+ end
425
+ Wagn::Log::Performance.with_timer(method_name, log_args) do
426
+ bind_block.call(self, args, &block)
215
427
  end
216
-
217
- @@log << Wagn::Log::Performance::Entry.new(parent, level, args )
218
- @@current_level += 1
219
- @@active_entries << @@log.last
220
-
221
- @@log.last
222
- end
223
-
224
- def finish_entry entry
225
- min_time = Wagn.config.performance_logger[:min_time]
226
- max_depth = Wagn.config.performance_logger[:max_depth]
227
- if (max_depth && entry.level > max_depth) || (min_time && entry.duration < min_time)
228
- entry.delete
229
428
  end
230
- @@active_entries.pop
231
- @@current_level -= 1
232
429
  end
233
-
430
+
431
+ def log_options_variable_name method_name, define_method
432
+ "@_#{self.class.name}_#{method_name.hash.to_s.sub(/^-/,'_')}_#{define_method}_logging_options".to_sym
433
+ end
434
+
234
435
  end
436
+
437
+
235
438
  end
236
439
 
237
440
  end