wagn 1.14.7 → 1.14.8

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