card 1.16.14 → 1.16.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/db/migrate_core_cards/20150903130006_attachment_upload_cards.rb +4 -2
  4. data/lib/card/auth.rb +15 -10
  5. data/lib/card/codename.rb +25 -21
  6. data/lib/card/content.rb +100 -68
  7. data/lib/card/format.rb +158 -129
  8. data/lib/card/query.rb +15 -9
  9. data/lib/card/query/attributes.rb +41 -49
  10. data/lib/card/set.rb +15 -12
  11. data/lib/card/set_pattern.rb +4 -5
  12. data/lib/card/spec_helper.rb +54 -16
  13. data/lib/cardio.rb +43 -25
  14. data/mod/01_core/chunk/include.rb +1 -1
  15. data/mod/01_core/set/all/collection.rb +76 -73
  16. data/mod/01_core/set/all/content.rb +0 -4
  17. data/mod/01_core/set/all/fetch.rb +35 -42
  18. data/mod/01_core/set/all/name.rb +17 -7
  19. data/mod/01_core/set/all/pattern.rb +12 -11
  20. data/mod/01_core/set/all/permissions.rb +51 -42
  21. data/mod/01_core/set/all/phases.rb +2 -1
  22. data/mod/01_core/set/all/references.rb +2 -2
  23. data/mod/01_core/set/all/rules.rb +28 -35
  24. data/mod/01_core/set/all/subcards.rb +12 -12
  25. data/mod/01_core/set/all/tracked_attributes.rb +1 -1
  26. data/mod/01_core/set/all/type.rb +11 -11
  27. data/mod/01_core/set/all/utils.rb +6 -1
  28. data/mod/01_core/spec/set/all/fetch_spec.rb +6 -6
  29. data/mod/01_core/spec/set/all/permissions_spec.rb +11 -11
  30. data/mod/01_core/spec/set/all/tracked_attributes_spec.rb +1 -1
  31. data/mod/01_history/lib/card/action.rb +52 -47
  32. data/mod/01_history/set/all/actions.rb +20 -16
  33. data/mod/01_history/set/all/history.rb +18 -13
  34. data/mod/02_basic_types/set/all/base.rb +23 -2
  35. data/mod/02_basic_types/set/type/pointer.rb +45 -36
  36. data/mod/02_basic_types/spec/set/all/base_spec.rb +40 -24
  37. data/mod/02_basic_types/spec/set/type/pointer_spec.rb +87 -0
  38. data/mod/03_machines/set/right/machine_output.rb +10 -6
  39. data/mod/04_settings/set/abstract/permission.rb +10 -5
  40. data/mod/04_settings/set/type/setting.rb +4 -1
  41. data/mod/05_email/set/all/follow.rb +39 -44
  42. data/mod/05_email/set/all/notify.rb +4 -1
  43. data/mod/05_email/set/right/followers.rb +16 -14
  44. data/mod/05_email/set/self/follow_defaults.rb +22 -19
  45. data/mod/05_standard/lib/carrier_wave/cardmount.rb +1 -0
  46. data/mod/05_standard/set/abstract/attachment.rb +85 -58
  47. data/mod/05_standard/set/all/comment.rb +35 -19
  48. data/mod/05_standard/set/all/error.rb +124 -98
  49. data/mod/05_standard/set/all/list_changes.rb +27 -22
  50. data/mod/05_standard/set/all/rich_html/editing.rb +96 -70
  51. data/mod/05_standard/set/all/rich_html/form.rb +123 -81
  52. data/mod/05_standard/set/all/rich_html/modal.rb +15 -58
  53. data/mod/05_standard/set/right/account.rb +2 -2
  54. data/mod/05_standard/set/right/email.rb +3 -2
  55. data/mod/05_standard/set/rstar/rules.rb +3 -3
  56. data/mod/05_standard/set/self/search.rb +45 -22
  57. data/mod/05_standard/set/type/cardtype.rb +13 -11
  58. data/mod/05_standard/set/type/listed_by.rb +3 -2
  59. data/mod/05_standard/set/type/set.rb +17 -13
  60. data/mod/05_standard/set/type/signup.rb +1 -2
  61. data/mod/05_standard/set/type/user.rb +1 -1
  62. data/mod/05_standard/spec/set/all/account_spec.rb +1 -1
  63. data/mod/05_standard/spec/set/all/history_spec.rb +1 -1
  64. data/mod/05_standard/spec/set/type/email_template_spec.rb +140 -134
  65. data/mod/05_standard/spec/set/type/image_spec.rb +2 -1
  66. data/mod/05_standard/spec/set/type/signup_spec.rb +2 -2
  67. data/spec/models/card/trash_spec.rb +1 -1
  68. data/spec/spec_helper.rb +0 -1
  69. metadata +2 -2
@@ -57,41 +57,47 @@ class Card
57
57
  conjunction: %w( and or all any ),
58
58
  special: %w( found_by not sort match complete extension_type ),
59
59
  ignore: %w( prepend append view params vars size )
60
- }.inject({}) {|h,pair| pair[1].each { |v| h[v.to_sym]=pair[0] }; h }
60
+ }.inject({}) { |h, pair| pair[1].each { |v| h[v.to_sym] = pair[0] }; h }
61
61
 
62
62
  CONJUNCTIONS = { any: :or, in: :or, or: :or, all: :and, and: :and }
63
63
 
64
64
  MODIFIERS = %w( conj return sort sort_as group dir limit offset )
65
- .inject({}) { |h,v| h[v.to_sym]=nil; h }
65
+ .inject({}) { |h,v| h[v.to_sym] = nil; h }
66
66
 
67
67
  OPERATORS = %w( != = =~ < > in ~ ).inject({}) {|h,v| h[v]=v; h }.merge({
68
- eq: '=', gt: '>', lt: '<', match: '~', ne: '!=', :'not in'=> nil
68
+ eq: '=', gt: '>', lt: '<', match: '~', ne: '!=', 'not in' => nil
69
69
  }.stringify_keys)
70
70
 
71
71
  DEFAULT_ORDER_DIRS = { :update => "desc", :relevance => "desc" }
72
72
 
73
73
  attr_reader :statement, :mods, :conditions, :comment,
74
- :subqueries, :superquery
74
+ :subqueries, :superquery
75
75
  attr_accessor :joins, :table_seq, :unjoined, :conditions_on_join
76
76
 
77
77
  def initialize statement, comment=nil
78
- @comment = comment
79
78
  @subqueries = []
80
79
  @conditions = []
81
80
  @joins = []
82
81
  @mods = {}
83
82
  @statement = statement.clone
84
83
 
85
- @unjoined = @statement.delete(:unjoined ) || nil
86
- @context = @statement.delete(:context ) || nil
84
+ @context = @statement.delete(:context) || nil
85
+ @unjoined = @statement.delete(:unjoined) || nil
87
86
  @superquery = @statement.delete(:superquery) || nil
88
- @vars = @statement.delete(:vars ) || {}
87
+ @vars = @statement.delete(:vars) || {}
89
88
  @vars.symbolize_keys!
90
89
 
90
+ @comment = comment || default_comment
91
+
91
92
  interpret @statement
92
93
  self
93
94
  end
94
95
 
96
+ def default_comment
97
+ return if @superquery || !Card.config.sql_comments
98
+ statement.to_s
99
+ end
100
+
95
101
  # Query Execution
96
102
  # By default a query returns card objects. This is accomplished by returning
97
103
  # a card identifier from SQL and then hooking into our caching system (see
@@ -185,7 +191,7 @@ class Card
185
191
  def normalize_value val
186
192
  case val
187
193
  when Integer, Float, Symbol, Hash then val
188
- when String, Card::Name then normalize_string_value val
194
+ when String, SmartName then normalize_string_value val
189
195
  when Array then val.map { |v| normalize_value v }
190
196
  else fail BadQuery, "unknown WQL value type: #{val.class}"
191
197
  end
@@ -26,12 +26,12 @@ class Card
26
26
  def editor_of val
27
27
  act_join = Join.new(
28
28
  from: self,
29
- to: ['card_acts', "a#{table_id force=true}", 'actor_id']
29
+ to: ['card_acts', "a#{table_id true}", 'actor_id']
30
30
  )
31
31
  joins << act_join
32
32
  action_join = Join.new(
33
33
  from: act_join,
34
- to: ['card_actions', "an#{table_id force=true}", 'card_act_id'],
34
+ to: ['card_actions', "an#{table_id true}", 'card_act_id'],
35
35
  superjoin: act_join
36
36
  )
37
37
  join_cards val, from: action_join, from_field: 'card_id'
@@ -40,13 +40,13 @@ class Card
40
40
  def edited_by val
41
41
  action_join = Join.new(
42
42
  from: self,
43
- to: ['card_actions', "an#{table_id force=true}", 'card_id']
43
+ to: ['card_actions', "an#{table_id true}", 'card_id']
44
44
  )
45
45
  joins << action_join
46
46
  act_join = Join.new(
47
47
  from: action_join,
48
48
  from_field: 'card_act_id',
49
- to: ['card_acts', "a#{table_id force=true}"]
49
+ to: ['card_acts', "a#{table_id true}"]
50
50
  )
51
51
  join_cards val, from: act_join, from_field: 'actor_id'
52
52
  end
@@ -100,72 +100,68 @@ class Card
100
100
  def found_by val
101
101
  found_by_cards(val).compact.each do |c|
102
102
  if c && [SearchTypeID, SetID].include?(c.type_id)
103
- #FIXME - move this check to set mods!
103
+ # FIXME: - move this check to set mods!
104
104
 
105
105
  subquery(
106
106
  c.get_query.merge unjoined: true, context: c.name
107
107
  )
108
108
  else
109
109
  raise BadQuery,
110
- '"found_by" value must be valid Search, ' +
111
- "but #{c.name} is a #{c.type_name}"
110
+ '"found_by" value must be valid Search, ' \
111
+ "but #{c.name} is a #{c.type_name}"
112
112
  end
113
113
  end
114
114
  end
115
115
 
116
-
117
116
  def found_by_cards val
118
- if Hash===val
117
+ if val.is_a? Hash
119
118
  Query.run val
120
119
  else
121
120
  Array.wrap(val).map do |v|
122
- Card.fetch val.to_name.to_absolute(context), :new=>{}
121
+ Card.fetch v.to_name.to_absolute(context), new: {}
123
122
  end
124
123
  end
125
-
126
124
  end
127
125
 
128
- def match(val)
126
+ def match val
129
127
  cxn, val = match_prep val
130
128
  val.gsub! /[^#{Card::Name::OK4KEY_RE}]+/, ' '
131
129
  return nil if val.strip.empty?
132
130
 
133
131
  val_list = val.split(/\s+/).map do |v|
134
132
  name_or_content = [
135
- "replace(#{self.table_alias}.name,'+',' ')",
136
- "#{self.table_alias}.db_content"
133
+ "replace(#{table_alias}.name,'+',' ')",
134
+ "#{table_alias}.db_content"
137
135
  ].map do |field|
138
- %{#{field} #{ cxn.match quote("[[:<:]]#{v}[[:>:]]") }}
136
+ %{#{field} #{cxn.match quote("[[:<:]]#{v}[[:>:]]")}}
139
137
  end
140
138
  "(#{name_or_content.join ' OR '})"
141
139
  end
142
140
  add_condition "(#{val_list.join ' AND '})"
143
141
  end
144
142
 
145
-
146
- def complete(val)
147
- no_plus_card = (val =~ /\+/ ? '' : "and right_id is null")
148
- # FIXME -- this should really be more nuanced --
143
+ def complete val
144
+ no_plus_card = (val =~ /\+/ ? '' : 'and right_id is null')
145
+ # FIXME: -- this should really be more nuanced --
149
146
  # it breaks down after one plus
150
147
 
151
148
  add_condition(
152
- " lower(name) LIKE lower(#{quote(val.to_s+'%')}) #{no_plus_card}"
149
+ " lower(#{table_alias}.name) LIKE" \
150
+ " lower(#{quote(val.to_s + '%')}) #{no_plus_card}"
153
151
  )
154
152
  end
155
153
 
156
- def extension_type val
154
+ def extension_type _val
157
155
  # DEPRECATED LONG AGO!!!
158
- Rails.logger.info "using DEPRECATED extension_type in WQL"
159
- interpret :right_plus => AccountID
156
+ Rails.logger.info 'using DEPRECATED extension_type in WQL'
157
+ interpret right_plus: AccountID
160
158
  end
161
159
 
162
-
163
160
  # ATTRIBUTE HELPERS
164
161
 
165
-
166
162
  def join_references key, val
167
- r = Reference.new( key, val, self )
168
- refjoin = Join.new(:from=>self, :to=>r, :to_field=>r.infield)
163
+ r = Reference.new(key, val, self)
164
+ refjoin = Join.new(from: self, to: r, to_field: r.infield)
169
165
  joins << refjoin
170
166
  if r.cardquery
171
167
  join_cards r.cardquery, from: refjoin, from_field: r.outfield
@@ -188,37 +184,35 @@ class Card
188
184
  if sort_field == 'count'
189
185
  sort_by_count val, item
190
186
  else
191
- if join_field = SORT_JOIN_TO_ITEM_MAP[item.to_sym]
192
- sq = join_cards val,
193
- to_field: join_field,
194
- side: 'LEFT',
195
- conditions_on_join: true
187
+ if (join_field = SORT_JOIN_TO_ITEM_MAP[item.to_sym])
188
+ sq = join_cards(val, to_field: join_field,
189
+ side: 'LEFT',
190
+ conditions_on_join: true)
196
191
  @mods[:sort] ||= "#{sq.table_alias}.#{sort_field}"
197
192
  else
198
193
  raise BadQuery, "sort item: #{item} not yet implemented"
199
194
  end
200
195
  end
201
-
202
196
  end
203
197
 
204
198
  # EXPERIMENTAL!
205
199
  def sort_by_count val, item
206
200
  if item == 'referred_to'
207
- @mods[:sort] = "coalesce(count,0)" # needed for postgres
201
+ @mods[:sort] = 'coalesce(count,0)' # needed for postgres
208
202
  cs = Query.new(
209
- :return=>'coalesce(count(*), 0) as count',
210
- :group=>'sort_join_field',
211
- :superquery=>self
203
+ return: 'coalesce(count(*), 0) as count',
204
+ group: 'sort_join_field',
205
+ superquery: self
212
206
  )
213
207
  subselect = Query.new(val.merge return: 'id', superquery: self)
214
208
  cs.add_condition "referer_id in (#{subselect.sql})"
215
- # FIXME - SQL generated before SQL phase
209
+ # FIXME: - SQL generated before SQL phase
216
210
  cs.joins << Join.new(
217
211
  from: cs,
218
- to:['card_references', 'wr', 'referee_id']
212
+ to: ['card_references', 'wr', 'referee_id']
219
213
  )
220
214
  cs.mods[:sort_join_field] = "#{cs.table_alias}.id as sort_join_field"
221
- #HACK!
215
+ # HACK!
222
216
 
223
217
  joins << Join.new(
224
218
  from: self,
@@ -261,8 +255,7 @@ class Card
261
255
  s
262
256
  end
263
257
 
264
-
265
- #~~~~~~~ CONJUNCTION
258
+ # ~~~~~~~ CONJUNCTION
266
259
 
267
260
  def all val
268
261
  conjoin val, :and
@@ -276,8 +269,8 @@ class Card
276
269
  alias_method :in, :any
277
270
 
278
271
  def conjoin val, conj
279
- sq = subquery( unjoined: true, conj: conj )
280
- unless Array===val
272
+ sq = subquery unjoined: true, conj: conj
273
+ unless val.is_a? Array
281
274
  val = clause_to_hash(val).map { |key, value| { key => value } }
282
275
  end
283
276
  val.each do |val_item|
@@ -291,7 +284,7 @@ class Card
291
284
  end
292
285
 
293
286
  def restrict id_field, val
294
- if id = id_from_val(val)
287
+ if (id = id_from_val(val))
295
288
  interpret id_field => id
296
289
  else
297
290
  join_cards val, from_field: id_field
@@ -300,11 +293,10 @@ class Card
300
293
 
301
294
  def id_from_val val
302
295
  case val
303
- when Integer ; val
304
- when String ; Card.fetch_id(val)
296
+ when Integer then val
297
+ when String then Card.fetch_id(val)
305
298
  end
306
299
  end
307
-
308
300
  end
309
301
  end
310
- end
302
+ end
@@ -1,7 +1,6 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
 
3
3
  class Card
4
- # remove_const :Set if const_defined?(:Set, false)
5
4
 
6
5
  module Set
7
6
  mattr_accessor :modules, :traits
@@ -101,16 +100,16 @@ class Card
101
100
  else
102
101
  alias_block view, args
103
102
  end
104
- define_method "_view_#{ view }", view_block
103
+ define_method "_view_#{view}", view_block
105
104
  end
106
105
 
107
106
  def alias_block view, args
108
107
  opts = args[0].is_a?(Hash) ? args.shift : { view: args.shift }
109
- opts[:mod] ||= self
108
+ opts[:mod] ||= self
110
109
  opts[:view] ||= view
111
110
  views[opts[:mod]][opts[:view]] || fail
112
111
  rescue
113
- raise "cannot find #{ opts[:view] } view in #{ opts[:mod] }; " \
112
+ raise "cannot find #{opts[:view]} view in #{opts[:mod]}; " \
114
113
  "failed to alias #{view} in #{self}"
115
114
  end
116
115
  end
@@ -119,8 +118,8 @@ class Card
119
118
  if format_names.empty?
120
119
  format_names = [:base]
121
120
  elsif format_names.first == :all
122
- format_names = Card::Format.registered
123
- .reject { |f| Card::Format.aliases[f] }
121
+ format_names =
122
+ Card::Format.registered.reject { |f| Card::Format.aliases[f] }
124
123
  end
125
124
  format_names.each do |f|
126
125
  define_on_format f, &block
@@ -215,7 +214,6 @@ class Card
215
214
  def define_event_method event, call_method, _opts
216
215
  class_eval do
217
216
  define_method event do
218
- # Rails.logger.rspec event
219
217
  run_callbacks event do
220
218
  send call_method
221
219
  end
@@ -229,7 +227,8 @@ class Card
229
227
  # (when the job is executed ActiveJob fetches the card from the database so
230
228
  # all attributes get lost)
231
229
  # @param name [String] the name for the ActiveJob child class
232
- # @param final_method [String] the name of the card instance method to be queued
230
+ # @param final_method [String] the name of the card instance method to be
231
+ # queued
233
232
  # @option queue [Symbol] (:default) the name of the queue
234
233
  def define_active_job name, final_method, queue=:default
235
234
  class_name = name.to_s.camelize
@@ -240,12 +239,13 @@ class Card
240
239
  }
241
240
  Object.const_get(class_name).class_eval do
242
241
  define_method :perform, proc { |card, attributes|
243
- attributes.each do |name, args|
242
+ attributes.each do |attname, args|
244
243
  # symbols are not allowed so all symbols arrive here as strings
245
244
  # convert strings that were symbols before back to symbols
246
245
  value = args[:symbol] ? args[:value].to_sym : args[:value]
247
- card.instance_variable_set("@#{name}", value)
246
+ card.instance_variable_set("@#{attname}", value)
248
247
  end
248
+ card.include_set_modules
249
249
  card.send final_method
250
250
  }
251
251
  end
@@ -480,8 +480,11 @@ EOF
480
480
 
481
481
  def attachment name, args
482
482
  include Abstract::Attachment
483
- set_specific_attributes name, :load_from_mod, :action_id_of_cached_upload,
484
- "remote_#{name}_url".to_sym
483
+ set_specific_attributes name,
484
+ :load_from_mod,
485
+ :action_id_of_cached_upload,
486
+ :empty_ok,
487
+ "remote_#{name}_url".to_sym
485
488
  uploader_class = args[:uploader] || FileUploader
486
489
  mount_uploader name, uploader_class
487
490
  end
@@ -1,14 +1,13 @@
1
1
  class Card
2
-
3
2
  class SetPattern
4
-
5
3
  class << self
6
- attr_accessor :pattern_code, :pattern_id, :junction_only, :assigns_type, :anchorless, :anchor_parts_count
4
+ attr_accessor :pattern_code, :pattern_id, :junction_only, :assigns_type,
5
+ :anchorless, :anchor_parts_count
7
6
 
8
7
  def card_keys
9
8
  @@card_keys ||= Card.set_patterns.inject({}) do |hash, set_pattern|
10
- card_key = Card.fetch( set_pattern.pattern_code.to_sym, skip_modules: true ).key
11
- hash[ card_key ] = true
9
+ card_key = Card.quick_fetch(set_pattern.pattern_code.to_sym).key
10
+ hash[card_key] = true
12
11
  hash
13
12
  end
14
13
  end
@@ -1,26 +1,23 @@
1
1
  module SpecHelper
2
2
  end
3
3
  module Card::SpecHelper
4
-
5
4
  include Rails::Dom::Testing::Assertions::SelectorAssertions
6
- #~~~~~~~~~ HELPER METHODS ~~~~~~~~~~~~~~~#
5
+ # ~~~~~~~~~ HELPER METHODS ~~~~~~~~~~~~~~~#
7
6
 
8
7
  def login_as user
9
- Card::Auth.current_id = (uc=Card[user.to_s] and uc.id)
10
- if @request
11
- @request.session[:user] = Card::Auth.current_id
12
- end
13
- #warn "(ath)login_as #{user.inspect}, #{Card::Auth.current_id}, #{@request.session[:user]}"
8
+ Card::Auth.current_id = (uc = Card[user.to_s]) && uc.id
9
+ return unless @request
10
+ @request.session[:user] = Card::Auth.current_id
11
+ # warn "(ath)login_as #{user.inspect}, #{Card::Auth.current_id}, #{@request.session[:user]}"
14
12
  end
15
13
 
16
- def newcard name, content=""
14
+ def newcard name, content=''
17
15
  #FIXME - misleading name; sounds like it doesn't save.
18
16
  Card.create! name: name, content: content
19
17
  end
20
18
 
21
- def assert_view_select(view_html, *args, &block)
19
+ def assert_view_select view_html, *args, &block
22
20
  node = Nokogiri::HTML::Document.parse(view_html).root
23
- #node = HTML::Document.new(view_html).root
24
21
  if block_given?
25
22
  assert_select node, *args, &block
26
23
  else
@@ -28,9 +25,9 @@ module Card::SpecHelper
28
25
  end
29
26
  end
30
27
 
31
- def debug_assert_view_select(view_html, *args, &block)
28
+ def debug_assert_view_select view_html, *args, &block
32
29
  Rails.logger.rspec %(
33
- #{CodeRay.scan(Nokogiri::XML(view_html,&:noblanks).to_s, :html).div}
30
+ #{CodeRay.scan(Nokogiri::XML(view_html, &:noblanks).to_s, :html).div}
34
31
  <style>
35
32
  .CodeRay {
36
33
  background-color: #FFF;
@@ -43,17 +40,17 @@ module Card::SpecHelper
43
40
  assert_view_select view_html, *args, &block
44
41
  end
45
42
 
46
- def render_editor(type)
43
+ def render_editor type
47
44
  card = Card.create(name: "my favority #{type} + #{rand(4)}", type: type)
48
45
  card.format.render(:edit)
49
46
  end
50
47
 
51
48
  def render_content content, format_args={}
52
- render_content_with_args( content, format_args )
49
+ render_content_with_args content, format_args
53
50
  end
54
51
 
55
52
  def render_content_with_args content, format_args={}, view_args={}
56
- @card ||= Card.new name: "Tempo Rary 2"
53
+ @card ||= Card.new name: 'Tempo Rary 2'
57
54
  @card.content = content
58
55
  @card.format(format_args)._render :core, view_args
59
56
  end
@@ -67,7 +64,7 @@ module Card::SpecHelper
67
64
  if card_args[:name]
68
65
  Card.fetch card_args[:name], new: card_args
69
66
  else
70
- Card.new card_args.merge( name: 'Tempo Rary' )
67
+ Card.new card_args.merge(name: 'Tempo Rary')
71
68
  end
72
69
  end
73
70
  card.format(format_args)._render(view, view_args)
@@ -76,4 +73,45 @@ module Card::SpecHelper
76
73
  def users
77
74
  SharedData::USERS.sort
78
75
  end
76
+
77
+ # Make expectations in the event phase.
78
+ # Takes the usual event options :on and :before/:after/:around
79
+ # and registers the event_block with these options as an event.
80
+ # Unknown methods in the event_block are executed in the rspec context
81
+ # instead of the card's context.
82
+ # An additionaly :trigger block in opts is expected that is called
83
+ # to start the event phase.
84
+ # Example:
85
+ # in_phase before: :approve, on: :save,
86
+ # trigger: ->{ test_card.update_attributes! content: '' } do
87
+ # expect(item_names).to eq []
88
+ # end
89
+ def in_phase opts, &event_block
90
+ $rspec_binding = binding
91
+ Card.class_eval do
92
+ def method_missing m, *args
93
+ begin
94
+ method = eval('method(%s)' % m.inspect, $rspec_binding)
95
+ rescue NameError
96
+ else
97
+ return method.call(*args)
98
+ end
99
+ begin
100
+ value = eval(m.to_s, $rspec_binding)
101
+ return value
102
+ rescue NameError
103
+ end
104
+ super
105
+ # raise NoMethodError
106
+ end
107
+ define_method :in_phase_test, event_block
108
+ end
109
+ Card.define_callbacks :in_phase_test
110
+ kind = ([:before, :after, :around] & opts.keys).first
111
+ name = opts.delete(kind)
112
+ Card.set_callback name, kind, :in_phase_test, prepend: true
113
+ opts[:trigger].call
114
+ ensure
115
+ Card.skip_callback name, kind, :in_phase_test
116
+ end
79
117
  end