card 1.16.8 → 1.16.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/db/migrate_core_cards/{20150611203506_rails_inflection_updates.rb → 20120611203506_rails_inflection_updates.rb} +0 -0
  4. data/db/migrate_core_cards/20150326205655_bootswatch_themes.rb +0 -1
  5. data/db/migrate_core_cards/20150429090551_search_card_context.rb +1 -1
  6. data/db/migrate_core_cards/20150708224756_add_list_cards.rb +22 -0
  7. data/db/seed/new/card_actions.yml +789 -509
  8. data/db/seed/new/card_acts.yml +1 -1
  9. data/db/seed/new/card_changes.yml +2618 -1920
  10. data/db/seed/new/card_references.yml +1034 -901
  11. data/db/seed/new/cards.yml +2303 -1675
  12. data/db/seed/test/fixtures/card_actions.yml +1926 -1606
  13. data/db/seed/test/fixtures/card_acts.yml +354 -324
  14. data/db/seed/test/fixtures/card_changes.yml +5950 -5175
  15. data/db/seed/test/fixtures/card_references.yml +1861 -1630
  16. data/db/seed/test/fixtures/cards.yml +3768 -3048
  17. data/db/seed/test/seed.rb +121 -107
  18. data/lib/card.rb +2 -3
  19. data/lib/card/active_record_helper.rb +44 -0
  20. data/lib/card/auth.rb +51 -47
  21. data/lib/card/cache.rb +7 -3
  22. data/lib/card/codename.rb +7 -7
  23. data/lib/card/format.rb +2 -1
  24. data/lib/card/migration.rb +17 -16
  25. data/lib/card/name.rb +71 -20
  26. data/lib/card/set.rb +202 -166
  27. data/lib/card/simplecov_helper.rb +11 -7
  28. data/lib/card/subcards.rb +249 -0
  29. data/mod/01_core/set/all/collection.rb +1 -2
  30. data/mod/01_core/set/all/fetch.rb +167 -92
  31. data/mod/01_core/set/all/initialize.rb +8 -22
  32. data/mod/01_core/set/all/name.rb +128 -79
  33. data/mod/01_core/set/all/phases.rb +93 -95
  34. data/mod/01_core/set/all/subcards.rb +70 -0
  35. data/mod/01_core/set/all/tracked_attributes.rb +83 -59
  36. data/mod/01_core/set/all/trash.rb +14 -12
  37. data/mod/01_core/set/all/type.rb +3 -24
  38. data/mod/01_core/spec/set/all/initialize_spec.rb +44 -14
  39. data/mod/01_core/spec/set/all/permissions_spec.rb +206 -185
  40. data/mod/01_core/spec/set/all/tracked_attributes_spec.rb +0 -10
  41. data/mod/01_core/spec/set/all/trash_spec.rb +38 -13
  42. data/mod/01_core/spec/set/all/type_spec.rb +0 -19
  43. data/mod/01_history/set/all/content_history.rb +5 -3
  44. data/mod/01_history/set/all/history.rb +117 -82
  45. data/mod/02_basic_types/set/all/base.rb +50 -49
  46. data/mod/03_machines/lib/card/machine.rb +2 -1
  47. data/mod/03_machines/lib/javascript/wagn_mod.js.coffee +55 -17
  48. data/mod/03_machines/spec/set/type/javascript_spec.rb +18 -12
  49. data/mod/05_email/set/right/followers.rb +5 -5
  50. data/mod/05_email/set/right/following.rb +1 -1
  51. data/mod/05_email/set/type_plus_right/user/follow.rb +1 -1
  52. data/mod/05_standard/lib/carrier_wave/cardmount.rb +19 -11
  53. data/mod/05_standard/lib/file_uploader.rb +1 -1
  54. data/mod/05_standard/set/abstract/attachment.rb +20 -8
  55. data/mod/05_standard/set/all/list_changes.rb +43 -0
  56. data/mod/05_standard/set/all/rich_html/form.rb +21 -11
  57. data/mod/05_standard/set/all/rich_html/menu.rb +1 -1
  58. data/mod/05_standard/set/right/account.rb +5 -5
  59. data/mod/05_standard/set/self/head.rb +0 -1
  60. data/mod/05_standard/set/self/signin.rb +43 -35
  61. data/mod/05_standard/set/type/file.rb +9 -2
  62. data/mod/05_standard/set/type/list.rb +134 -0
  63. data/mod/05_standard/set/type/listed_by.rb +94 -0
  64. data/mod/05_standard/set/type/search_type.rb +62 -61
  65. data/mod/05_standard/set/type/signup.rb +94 -63
  66. data/mod/05_standard/set/type/user.rb +48 -39
  67. data/mod/05_standard/spec/set/all/account_spec.rb +1 -1
  68. data/mod/05_standard/spec/set/all/rich_html/form_spec.rb +2 -2
  69. data/mod/05_standard/spec/set/self/signin_spec.rb +23 -27
  70. data/mod/05_standard/spec/set/type/email_template_spec.rb +0 -2
  71. data/mod/05_standard/spec/set/type/list_spec.rb +140 -0
  72. data/mod/05_standard/spec/set/type/listed_by_spec.rb +157 -0
  73. data/mod/05_standard/spec/set/type/signup_spec.rb +38 -32
  74. data/spec/lib/card/subcards_spec.rb +126 -0
  75. metadata +14 -3
data/lib/card/cache.rb CHANGED
@@ -147,7 +147,7 @@ class Card
147
147
 
148
148
  def write_variable key, variable, value
149
149
  key = @prefix + key
150
- if @store and object = @store.read(key)
150
+ if @store && (object = @store.read key)
151
151
  object.instance_variable_set "@#{ variable }", value
152
152
  @store.write key, object
153
153
  end
@@ -174,7 +174,7 @@ class Card
174
174
  end
175
175
 
176
176
  def fetch_local key
177
- read_local key or write_local key, yield
177
+ read_local(key) || write_local(key, yield)
178
178
  end
179
179
 
180
180
  def delete key
@@ -182,6 +182,10 @@ class Card
182
182
  @local.delete key
183
183
  end
184
184
 
185
+ def delete_local key
186
+ @local.delete key
187
+ end
188
+
185
189
  def dump
186
190
  p "dumping local...."
187
191
  @local.each do |k, v|
@@ -211,7 +215,7 @@ class Card
211
215
  end
212
216
 
213
217
  def exist? key
214
- @local.has_key?(key) || @store.exist?(key)
218
+ @local.has_key?(key) || (@store && @store.exist?(key))
215
219
  end
216
220
  end
217
221
  end
data/lib/card/codename.rb CHANGED
@@ -29,10 +29,10 @@ class Card
29
29
  def bootdata hash
30
30
  @@codehash = hash
31
31
  end
32
-
33
-
32
+
33
+
34
34
  private
35
-
35
+
36
36
  def cache
37
37
  Card::Cache[Codename]
38
38
  end
@@ -53,10 +53,10 @@ class Card
53
53
  end
54
54
  end
55
55
  end
56
-
56
+
57
57
  end
58
-
59
-
58
+
59
+
60
60
  def self.const_missing const
61
61
  if const.to_s =~ /^([A-Z]\S*)ID$/ and code=$1.underscore.to_sym
62
62
  if card_id = Codename[code]
@@ -68,5 +68,5 @@ class Card
68
68
  super
69
69
  end
70
70
  end
71
-
71
+
72
72
  end
data/lib/card/format.rb CHANGED
@@ -204,7 +204,8 @@ class Card
204
204
  args = default_render_args view, args
205
205
  with_inclusion_mode view do
206
206
  Card::ViewCache.fetch(self, view, args) do
207
- send "_view_#{ view }", args
207
+ method = method "_view_#{ view }"
208
+ method.arity == 0 ? method.call : method.call(args)
208
209
  end
209
210
  end
210
211
  end
@@ -1,16 +1,17 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
 
3
3
  class Card::Migration < ActiveRecord::Migration
4
+ include Card::ActiveRecordHelper
4
5
  @type = :deck_cards
5
6
 
6
7
  class << self
7
-
8
8
  # Rake tasks use class methods, migrations use instance methods.
9
- # To avoid repetition a lot of instance methods here just call class methods.
9
+ # To avoid repetition a lot of instance methods here just call class
10
+ # methods.
10
11
  # The subclass Card::CoreMigration needs a different @type so we can't use a
11
12
  # class variable @@type. It has to be a class instance variable.
12
- # Migrations are subclasses of Card::Migration or Card::CoreMigration but they
13
- # don't inherit the @type. The method below solves this problem.
13
+ # Migrations are subclasses of Card::Migration or Card::CoreMigration
14
+ # but they don't inherit the @type. The method below solves this problem.
14
15
  def type
15
16
  @type || (ancestors[1] && ancestors[1].type)
16
17
  end
@@ -18,9 +19,9 @@ class Card::Migration < ActiveRecord::Migration
18
19
  def find_unused_name base_name
19
20
  test_name = base_name
20
21
  add = 1
21
- while Card.exists?(test_name) do
22
+ while Card.exists?(test_name)
22
23
  test_name = "#{base_name}#{add}"
23
- add +=1
24
+ add += 1
24
25
  end
25
26
  test_name
26
27
  end
@@ -50,18 +51,18 @@ class Card::Migration < ActiveRecord::Migration
50
51
 
51
52
  def assume_migrated_upto_version
52
53
  schema_mode do
53
- ActiveRecord::Schema.assume_migrated_upto_version schema, migration_paths
54
+ ActiveRecord::Schema.assume_migrated_upto_version schema,
55
+ migration_paths
54
56
  end
55
57
  end
56
58
 
57
59
  def data_path filename=nil
58
60
  path = migration_paths.first
59
- File.join( [ migration_paths.first, 'data', filename ].compact )
61
+ File.join([path, 'data', filename].compact)
60
62
  end
61
-
62
63
  end
63
64
 
64
- def contentedly &block
65
+ def contentedly
65
66
  Card::Cache.reset_global
66
67
  Cardio.schema_mode '' do
67
68
  Card::Auth.as_bot do
@@ -78,14 +79,15 @@ class Card::Migration < ActiveRecord::Migration
78
79
 
79
80
  def import_json filename, merge_opts={}
80
81
  Card.config.action_mailer.perform_deliveries = false
81
- merge_opts.reverse_merge! output_file: File.join(data_path,"unmerged_#{ filename }")
82
+ output_file = File.join data_path, "unmerged_#{ filename }"
83
+ merge_opts[:output_file] ||= output_file
82
84
  Card.merge_list read_json(filename), merge_opts
83
85
  end
84
86
 
85
87
  def read_json filename
86
- raw_json = File.read( data_path filename )
88
+ raw_json = File.read data_path(filename)
87
89
  json = JSON.parse raw_json
88
- json["card"]["value"]
90
+ json['card']['value']
89
91
  end
90
92
 
91
93
  def data_path filename=nil
@@ -101,8 +103,8 @@ class Card::Migration < ActiveRecord::Migration
101
103
  end
102
104
 
103
105
  # Execute this migration in the named direction
104
- # copied from ActiveRecord to wrap "up" in "contentendly"
105
- def exec_migration(conn, direction)
106
+ # copied from ActiveRecord to wrap 'up' in 'contentendly'
107
+ def exec_migration conn, direction
106
108
  @connection = conn
107
109
  if respond_to?(:change)
108
110
  if direction == :down
@@ -117,7 +119,6 @@ class Card::Migration < ActiveRecord::Migration
117
119
  @connection = nil
118
120
  end
119
121
 
120
-
121
122
  def down
122
123
  raise ActiveRecord::IrreversibleMigration
123
124
  end
data/lib/card/name.rb CHANGED
@@ -5,61 +5,112 @@ require 'smart_name'
5
5
 
6
6
  class Card
7
7
  class Name < SmartName
8
+ RELATIVE_REGEXP = /\b_(left|right|whole|self|user|main|\d+|L*R?)\b/
8
9
 
9
10
  self.params = Card::Env # yuck!
10
11
  self.session = proc { Card::Auth.current.name }
11
12
  self.banned_array = ['/']
12
13
 
13
14
  def star?
14
- simple? and '*' == s[0,1]
15
+ simple? && '*' == s[0, 1]
15
16
  end
16
17
 
17
18
  def rstar?
18
- right and '*' == right[0,1]
19
+ right && '*' == right[0, 1]
19
20
  end
20
21
 
21
22
  def trait_name? *traitlist
22
23
  junction? && begin
23
24
  right_key = right_name.key
24
- !!traitlist.find do |codename|
25
- card_id = Card::Codename[ codename ] and card = Card.fetch( card_id, skip_modules: true, skip_virtual: true ) and
25
+ traitlist.find do |codename|
26
+ (card_id = Card::Codename[codename]) &&
27
+ (card = Card.quick_fetch card_id) &&
26
28
  card.key == right_key
27
- end
29
+ end.present?
28
30
  end
29
31
  end
30
32
 
31
33
  def trait_name tag_code
32
- card_id = Card::Codename[ tag_code ] and card = Card.fetch( card_id, skip_modules: true, skip_virtual: true ) and
33
- [ self, card.cardname ].to_name
34
+ (card_id = Card::Codename[tag_code]) &&
35
+ (card = Card.quick_fetch card_id) &&
36
+ [self, card.cardname].to_name
34
37
  end
35
38
 
36
39
  def trait tag_code
37
- name = trait_name( tag_code )
38
- name ? name.s : ( raise Card::NotFound, "unknown codename: #{tag_code}" )
40
+ name = trait_name(tag_code)
41
+ name ? name.s : (fail Card::NotFound, "unknown codename: #{tag_code}")
42
+ end
43
+
44
+ def field tag_name
45
+ field_name(tag_name).s
39
46
  end
40
47
 
41
48
  def code
42
- Card::Codename[ Card.fetch_id self ]
49
+ Card::Codename[Card.fetch_id self]
50
+ end
51
+
52
+ # returns full name for a field
53
+ def field_name tag_name
54
+ case tag_name
55
+ when Symbol
56
+ trait_name tag_name
57
+ else
58
+ if tag_name.to_s[0] == '+'
59
+ tag_name = tag_name.to_s[1..-1]
60
+ end
61
+ [ self, tag_name ].to_name
62
+ end
63
+ end
64
+
65
+ def relative_field_name tag_name
66
+ field_name(tag_name).relative_name(self)
67
+ end
68
+
69
+ def relative_name context_name
70
+ to_show(*context_name.to_name.parts).to_name
43
71
  end
44
72
 
73
+ def absolute_name context_name
74
+ to_absolute_name(context_name)
75
+ end
45
76
 
46
- def is_a_field_of? context_name
77
+ def field_of? context_name
47
78
  if context_name.present?
48
- # Do I still equal myself after I've been relativised in the context of context_name?
49
- relative_name = self.to_show(*context_name.to_name.parts).to_name
50
- absolute_name = self.to_absolute_name(context_name)
51
- relative_name.key != absolute_name.key
79
+ # Do I still equal myself after I've been relativised in the context
80
+ # of context_name?
81
+ relative_name(context_name).key != absolute_name(context_name).key
52
82
  else
53
- self.s.match /^\s*\+/
83
+ s.match(/^\s*\+/)
54
84
  end
55
85
  end
56
86
 
57
- def is_setting?
58
- Set::Type::Setting.member_names[ key ]
87
+ def setting?
88
+ Set::Type::Setting.member_names[key]
89
+ end
90
+
91
+ def set?
92
+ SetPattern.card_keys[tag_name.key]
93
+ end
94
+
95
+
96
+ def relative?
97
+ s =~ RELATIVE_REGEXP || starts_with_joint?
98
+ end
99
+
100
+ def absolute?
101
+ !relative?
102
+ end
103
+
104
+ def stripped
105
+ s.gsub RELATIVE_REGEXP, ''
106
+ end
107
+
108
+ def starts_with_joint?
109
+ s =~ /^\+/
59
110
  end
60
111
 
61
- def is_set?
62
- SetPattern.card_keys[ tag_name.key ]
112
+ def to_sym
113
+ s.to_sym
63
114
  end
64
115
  end
65
116
  end
data/lib/card/set.rb CHANGED
@@ -1,86 +1,91 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
 
3
3
  class Card
4
- #remove_const :Set if const_defined?(:Set, false)
4
+ # remove_const :Set if const_defined?(:Set, false)
5
5
 
6
6
  module Set
7
-
8
7
  mattr_accessor :modules, :traits
9
8
  @@modules = { base: [], base_format: {}, nonbase: {}, nonbase_format: {} }
10
9
 
11
-
12
- =begin
13
- A "Set" is a group of Cards to which "Rules" may be applied. Sets can be as specific as
14
- a single card, as general as all cards, or anywhere in between.
15
-
16
- Rules take two main forms: card rules and code rules.
17
-
18
- "Card rules" are defined in card content. These are generally configured via the web
19
- interface and are thus documented at http://wagn.org/rules.
20
-
21
- "Code rules" can be defined in a "set file" within any "Mod" (short for both "module" and
22
- "modification"). In accordance with Wagn's "MoVE" architecture, there are two main kinds of
23
- code rules you can create in a set file: Views, and Events. Events are associated with the
24
- Card class, and Views are associated with a Format class. You can also use set files to
25
- add or override Card and/or Format methods directly. The majority of Card code is contained
26
- in these files.
27
-
28
- (FIXME - define mod, add generator)
29
-
30
- Whenever you fetch or instantiate a card, it will automatically include all the
31
- set modules defined in set files associated with sets of which it is a member. This
32
- entails both simple model methods and "events", which are special methods explored
33
- in greater detail below.
34
-
35
- For example, say you have a Plaintext card named "Philipp+address", and you have set files
36
- for the following sets:
37
-
38
- * all cards
39
- * all Plaintext cards
40
- * all cards ending in +address
41
-
42
- When you run this:
43
-
44
- mycard = Card.fetch 'Philipp+address'
45
-
46
- ...then mycard will include the set modules associated with each of those sets in the above
47
- order. (The order is determined by the set pattern; see lib/card/set_pattern.rb for more
48
- information about set_ptterns and mod/core/set/all/fetch.rb for more about fetching.)
49
-
50
- Similarly, whenever a Format object is instantiated for a card, it includes all views
51
- associated with BOTH (a) sets of which the card is a member and (b) the current format or
52
- its ancestors. More on defining views below.
53
-
54
-
55
- In order to have a set file associated with "all cards ending in +address", you could create
56
- a file in mywagn/mod/mymod/set/right/address.rb. The recommended mechanism for doing so
57
- is running `wagn generate set modname set_pattern set_anchor`. In the current example, this
58
- would translate to `wagn generate set mymod right address`. Note that both the set_pattern
59
- and the set_anchor must correspond to the codename of a card in the database to function
60
- correctly but you can add arbitrary subdirectories to organize your code rules. The rule above
61
- for example could be saved in mywagn/mod/mymod/set/right/address/america/north/canada.rb.
62
-
63
-
64
- When a Card application loads, it uses these files to autogenerate a tmp_file that uses this set file to
65
- createa Card::Set::Right::Address module which itself is extended with Card::Set. A set file
66
- is "just ruby" but is generally quite concise because Card uses its file location to
67
- autogenerate ruby module names and then uses Card::Set module to provide additional API.
68
-
69
-
70
- View definitions
71
-
72
- When you declare:
73
- view :view_name do |args|
74
- #...your code here
75
- end
76
-
77
- Methods are defined on the format
78
-
79
- The external api with checks:
80
- render(:viewname, args)
81
-
82
-
83
- =end
10
+ # A 'Set' is a group of Cards to which 'Rules' may be applied.
11
+ # Sets can be as specific as a single card, as general as all cards, or
12
+ # anywhere in between.
13
+ #
14
+ # Rules take two main forms: card rules and code rules.
15
+ #
16
+ # 'Card rules' are defined in card content. These are generally configured
17
+ # via the web interface and are thus documented at http://wagn.org/rules.
18
+ #
19
+ # 'Code rules' can be defined in a 'set file' within any 'Mod' (short for
20
+ # both 'module' and 'modification'). In accordance with Wagn's 'MoVE'
21
+ # architecture, there are two main kinds of code rules you can create in
22
+ # set file: Views, and Events.
23
+ # Events are associated with the Card class, and Views are associated with
24
+ # a Format class.
25
+ # You can also use set files to add or override Card and/or Format methods
26
+ # directly. The majority of Card code is contained in these files.
27
+ #
28
+ # (FIXME - define mod, add generator)
29
+ #
30
+ # Whenever you fetch or instantiate a card, it will automatically include
31
+ # all the set modules defined in set files associated with sets of which it
32
+ # is a member. This entails both simple model methods and 'events', which
33
+ # are special methods explored in greater detail below.
34
+ #
35
+ # For example, say you have a Plaintext card named 'Philipp+address', and
36
+ # you have set files for the following sets:
37
+ #
38
+ # * all cards
39
+ # * all Plaintext cards
40
+ # * all cards ending in +address
41
+ #
42
+ # When you run this:
43
+ #
44
+ # mycard = Card.fetch 'Philipp+address'
45
+ #
46
+ # ...then mycard will include the set modules associated with each of those
47
+ # sets in the above order. (The order is determined by the set pattern;
48
+ # see lib/card/set_pattern.rb for more information about set_ptterns and
49
+ # mod/core/set/all/fetch.rb for more about fetching.)
50
+ #
51
+ # Similarly, whenever a Format object is instantiated for a card, it
52
+ # includes all views associated with BOTH (a) sets of which the card is a
53
+ # member and (b) the current format or its ancestors. More on defining
54
+ # views below.
55
+ #
56
+ #
57
+ # In order to have a set file associated with "all cards ending in
58
+ # +address", you could create a file in
59
+ # mywagn/mod/mymod/set/right/address.rb.
60
+ # The recommended mechanism for doing so is running `wagn generate set
61
+ # modname set_pattern set_anchor`. In the current example, this
62
+ # would translate to `wagn generate set mymod right address`.
63
+ # Note that both the set_pattern and the set_anchor must correspond to the
64
+ # codename of a card in the database to function correctly but you can add
65
+ # arbitrary subdirectories to organize your code rules. The rule above
66
+ # for example could be saved in
67
+ # mywagn/mod/mymod/set/right/address/america/north/canada.rb.
68
+ #
69
+ #
70
+ # When a Card application loads, it uses these files to autogenerate a
71
+ # tmp_file that uses this set file to create a Card::Set::Right::Address
72
+ # module which itself is extended with Card::Set. A set file is 'just ruby'
73
+ # but is generally quite concise because Card uses its file location to
74
+ # autogenerate ruby module names and then uses Card::Set module to provide
75
+ # additional API.
76
+ #
77
+ #
78
+ # View definitions
79
+ #
80
+ # When you declare:
81
+ # view :view_name do |args|
82
+ # #...your code here
83
+ # end
84
+ #
85
+ # Methods are defined on the format
86
+ #
87
+ # The external api with checks:
88
+ # render(:viewname, args)
84
89
 
85
90
  module Format
86
91
  mattr_accessor :views
@@ -89,32 +94,33 @@ class Card
89
94
  def view view, *args, &block
90
95
  view = view.to_viewname.key.to_sym
91
96
  views[self] ||= {}
92
- view_block = views[self][view] = if block_given?
93
- Card::Format.extract_class_vars view, args[0]
94
- block
95
- else
96
- alias_block view, args
97
- end
97
+ view_block = views[self][view] =
98
+ if block_given?
99
+ Card::Format.extract_class_vars view, args[0]
100
+ block
101
+ else
102
+ alias_block view, args
103
+ end
98
104
  define_method "_view_#{ view }", view_block
99
105
  end
100
106
 
101
107
  def alias_block view, args
102
- opts = Hash===args[0] ? args.shift : { view: args.shift }
108
+ opts = args[0].is_a?(Hash) ? args.shift : { view: args.shift }
103
109
  opts[:mod] ||= self
104
110
  opts[:view] ||= view
105
- views[ opts[:mod] ][ opts[:view] ] or fail
111
+ views[opts[:mod]][opts[:view]] || fail
106
112
  rescue
107
- raise "cannot find #{ opts[:view] } view in #{ opts[:mod] }; failed to alias #{view} in #{self}"
113
+ raise "cannot find #{ opts[:view] } view in #{ opts[:mod] }; " \
114
+ "failed to alias #{view} in #{self}"
108
115
  end
109
-
110
116
  end
111
117
 
112
-
113
118
  def format *format_names, &block
114
119
  if format_names.empty?
115
120
  format_names = [:base]
116
121
  elsif format_names.first == :all
117
- format_names = Card::Format.registered.reject {|f| Card::Format.aliases[f]}
122
+ format_names = Card::Format.registered
123
+ .reject { |f| Card::Format.aliases[f] }
118
124
  end
119
125
  format_names.each do |f|
120
126
  define_on_format f, &block
@@ -122,9 +128,12 @@ class Card
122
128
  end
123
129
 
124
130
  def define_on_format format_name=:base, &block
125
- klass = Card::Format.format_class_name format_name # format class name, eg. HtmlFormat
126
- mod = const_get_or_set klass do # called on current set module, eg Card::Set::Type::Pointer
127
- m = Module.new # yielding set format module, eg Card::Set::Type::Pointer::HtmlFormat
131
+ # format class name, eg. HtmlFormat
132
+ klass = Card::Format.format_class_name format_name
133
+ # called on current set module, eg Card::Set::Type::Pointer
134
+ mod = const_get_or_set klass do
135
+ # yielding set format module, eg Card::Set::Type::Pointer::HtmlFormat
136
+ m = Module.new
128
137
  register_set_format Card.const_get(klass), m
129
138
  m.extend Card::Set::Format
130
139
  m
@@ -138,11 +147,11 @@ class Card
138
147
  end
139
148
  end
140
149
 
141
-
142
150
  def event event, opts={}, &final
143
- perform_later = (opts[:before] == :subsequent) || (opts[:after] == :subsequent)
144
- final_method = "#{event}_without_callbacks" #should be private?
145
- opts[:on] = [:create, :update ] if opts[:on] == :save
151
+ perform_later = (opts[:before] == :subsequent) ||
152
+ (opts[:after] == :subsequent)
153
+ final_method = "#{event}_without_callbacks" # should be private?
154
+ opts[:on] = [:create, :update] if opts[:on] == :save
146
155
 
147
156
  Card.define_callbacks event
148
157
 
@@ -161,26 +170,53 @@ class Card
161
170
  set_event_callbacks event, opts
162
171
  end
163
172
 
173
+ def phase_method method, opts={}, &block
174
+ class_eval do
175
+ define_method "_#{method}", &block
176
+ define_method method do |*args|
177
+ error =
178
+ if !phase_ok? opts
179
+ if !phase
180
+ "phase method #{method} called outside of event phases"
181
+ else
182
+ "#{opts.inspect} method #{method} called in phase #{phase}"
183
+ end
184
+ elsif !on_condition_applies?(opts[:on])
185
+ "on: #{opts[:on]} method #{method} called on #{@action}"
186
+ end
187
+ if error
188
+ raise Card::Error, error
189
+ else
190
+ send "_#{method}", *args
191
+ end
192
+ end
193
+ end
194
+ end
195
+
164
196
  def define_event_perform_later_method event, method_name
165
197
  class_eval do
166
198
  define_method method_name, proc {
167
- s_attr = self.serializable_attributes.each_with_object({}) do |name, hash|
168
- value = self.instance_variable_get("@#{name}")
169
- hash[name] =
170
- if Symbol === value # ActiveJob doesn't accept symbols as arguments
171
- { value: value.to_s, symbol: true }
172
- else
173
- { value: value }
174
- end
199
+ s_attr =
200
+ serializable_attributes.each_with_object({}) do |name, hash|
201
+ value = instance_variable_get("@#{name}")
202
+ hash[name] =
203
+ # ActiveJob doesn't accept symbols as arguments
204
+ if Symbol === value
205
+ { value: value.to_s, symbol: true }
206
+ else
207
+ { value: value }
175
208
  end
209
+ end
176
210
  Object.const_get(event.to_s.camelize).perform_later(self, s_attr)
177
211
  }
178
212
  end
179
213
  end
180
214
 
181
- def define_event_method event, call_method, opts
215
+ def define_event_method event, call_method, _opts
182
216
  class_eval do
183
217
  define_method event do
218
+ # Rails.logger.rspec event
219
+ # puts "#{self.name}: #{event}"
184
220
  run_callbacks event do
185
221
  send call_method
186
222
  end
@@ -188,14 +224,15 @@ class Card
188
224
  end
189
225
  end
190
226
 
191
-
192
227
  # creates an Active Job.
193
- # The scheduled job gets the card object as argument and all serializable attributes of the card.
194
- # (when the job is executed ActiveJob fetches the card from the database so all attributes get lost)
228
+ # The scheduled job gets the card object as argument and all serializable
229
+ # attributes of the card.
230
+ # (when the job is executed ActiveJob fetches the card from the database so
231
+ # all attributes get lost)
195
232
  # @param name [String] the name for the ActiveJob child class
196
233
  # @param final_method [String] the name of the card instance method to be queued
197
234
  # @option queue [Symbol] (:default) the name of the queue
198
- def define_active_job name, final_method, queue = :default
235
+ def define_active_job name, final_method, queue=:default
199
236
  class_name = name.to_s.camelize
200
237
  eval %{
201
238
  class ::#{class_name} < ActiveJob::Base
@@ -203,15 +240,15 @@ class Card
203
240
  end
204
241
  }
205
242
  Object.const_get(class_name).class_eval do
206
- define_method :perform, proc { |card, attributes|
243
+ define_method :perform, proc { |card, attributes|
207
244
  attributes.each do |name, args|
208
245
  # symbols are not allowed so all symbols arrive here as strings
209
246
  # convert strings that were symbols before back to symbols
210
247
  value = args[:symbol] ? args[:value].to_sym : args[:value]
211
- card.instance_variable_set("@#{name}", value )
248
+ card.instance_variable_set("@#{name}", value)
212
249
  end
213
250
  card.send final_method
214
- }
251
+ }
215
252
  end
216
253
  end
217
254
 
@@ -220,47 +257,45 @@ class Card
220
257
  #
221
258
  def card_accessor *args
222
259
  options = args.extract_options!
223
- add_traits args, options.merge( reader: true, writer: true )
260
+ add_traits args, options.merge(reader: true, writer: true)
224
261
  end
225
262
 
226
263
  def card_reader *args
227
264
  options = args.extract_options!
228
- add_traits args, options.merge( reader: true )
265
+ add_traits args, options.merge(reader: true)
229
266
  end
230
267
 
231
268
  def card_writer *args
232
269
  options = args.extract_options!
233
- add_traits args, options.merge( writer: true )
270
+ add_traits args, options.merge(writer: true)
234
271
  end
235
272
 
236
-
237
273
  def ensure_set &block
238
274
  begin
239
275
  set_module = block.call
240
276
  rescue NameError => e
241
277
  if e.message.match /uninitialized constant (?:Card::Set::)?(.+)$/
242
- $1.split('::').inject(Card::Set) do |set_module, module_name|
243
- set_module.const_get_or_set module_name do
278
+ $1.split('::').inject(Card::Set) do |set_mod, module_name|
279
+ set_mod.const_get_or_set module_name do
244
280
  Module.new
245
281
  end
246
282
  end
247
283
  end
248
- ensure_set &block # try again - there might be another submodule that doesn't exist
284
+ # try again - there might be another submodule that doesn't exist
285
+ ensure_set &block
249
286
  else
250
287
  set_module.extend Card::Set
251
288
  end
252
289
  end
253
-
254
-
255
290
  # the set loading process has two main phases:
256
291
 
257
- # 1. Definition: interpret each set file, creating/defining set and set_format modules
258
- # 2. Organization: have base classes include modules associated with the "all" set, and
259
- # clean up the other modules
292
+ # 1. Definition: interpret each set file, creating/defining set and
293
+ # set_format modules
294
+ # 2. Organization: have base classes include modules associated with the
295
+ # 'all' set, and clean up the other modules
260
296
 
261
297
  class << self
262
-
263
- #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
298
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
264
299
  # Definition Phase
265
300
 
266
301
  # each set file calls `extend Card::Set` when loaded
@@ -268,44 +303,44 @@ class Card
268
303
  register_set mod
269
304
  end
270
305
 
271
-
272
306
  # make the set available for use
273
307
  def register_set set_module
274
- if set_module.abstract_set?
275
- # noop; only used by explicit inclusion in other set modules
276
- elsif set_module.all_set?
308
+ return if set_module.abstract_set? # noop; only used by explicit
309
+ # inclusion in other set modules
310
+ if set_module.all_set?
277
311
  # automatically included in Card class
278
- modules[ :base ] << set_module
312
+ modules[:base] << set_module
279
313
  else
280
314
  # made ready for dynamic loading via #include_set_modules
281
- modules[ :nonbase ][ set_module.shortname ] ||= []
282
- modules[ :nonbase ][ set_module.shortname ] << set_module
315
+ modules[:nonbase][set_module.shortname] ||= []
316
+ modules[:nonbase][set_module.shortname] << set_module
283
317
  end
284
318
  end
285
319
 
286
320
  def write_tmp_file from_file, to_file, rel_path
287
- name_parts = rel_path.gsub(/\.rb/,'').split(File::SEPARATOR)
321
+ name_parts = rel_path.gsub(/\.rb/, '').split(File::SEPARATOR)
288
322
  submodules = name_parts.map { |a| "module #{a.camelize};" } * ' '
289
323
  file_content = <<EOF
290
324
  # -*- encoding : utf-8 -*-
291
- class Card; module Set; #{submodules} extend Card::Set # ~~~~~~~~~~~ above autogenerated; below pulled from #{from_file} ~~~~~~~~~~~
325
+ class Card; module Set; #{submodules} extend Card::Set
326
+ # ~~~~~~~~~~~ above autogenerated; below pulled from #{from_file} ~~~~~~~~~~~
292
327
  #{ File.read from_file }
293
328
 
294
329
  # ~~~~~~~~~~~ below autogenerated; above pulled from #{from_file} ~~~~~~~~~~~
295
- end;end;#{'end;'*name_parts.size}
330
+ end;end;#{'end;' * name_parts.size}
296
331
  EOF
297
332
 
298
- FileUtils.mkdir_p to_file.gsub /[^\/]*$/, ''
333
+ FileUtils.mkdir_p File.dirname(to_file)
299
334
  File.write to_file, file_content
300
335
  to_file
301
336
  end
302
337
 
303
-
304
- #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
338
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
305
339
  # Organization Phase
306
340
 
307
- # "base modules" are modules that are permanently included on the Card or Format class
308
- # "nonbase modules" are included dynamically on singleton_classes
341
+ # 'base modules' are modules that are permanently included on the Card or
342
+ # Format class
343
+ # 'nonbase modules' are included dynamically on singleton_classes
309
344
  def process_base_modules
310
345
  process_base_module_list modules[:base], Card
311
346
  modules[:base_format].each do |format_class, modules_list|
@@ -320,15 +355,15 @@ EOF
320
355
  if mod.instance_methods.any?
321
356
  klass.send :include, mod
322
357
  end
323
- if class_methods = mod.const_get_if_defined( :ClassMethods )
358
+ if (class_methods = mod.const_get_if_defined(:ClassMethods))
324
359
  klass.send :extend, class_methods
325
360
  end
326
361
  end
327
362
  end
328
363
 
329
364
  def clean_empty_modules
330
- clean_empty_module_from_hash modules[ :nonbase ]
331
- modules[ :nonbase_format ].values.each do |hash|
365
+ clean_empty_module_from_hash modules[:nonbase]
366
+ modules[:nonbase_format].values.each do |hash|
332
367
  clean_empty_module_from_hash hash
333
368
  end
334
369
  end
@@ -339,22 +374,21 @@ EOF
339
374
  hash.delete mod_name if modlist.empty?
340
375
  end
341
376
  end
342
-
343
377
  end
344
378
 
345
-
346
379
  def register_set_format format_class, mod
347
- if self.abstract_set?
348
- # noop; only used by explicit inclusion in other set modules
349
- elsif self.all_set?
380
+ return if self.abstract_set? # noop; only used by explicit inclusion in
381
+ # other set modules
382
+
383
+ if self.all_set?
350
384
  # ready to include in base format classes
351
- modules[ :base_format ][ format_class ] ||= []
352
- modules[ :base_format ][ format_class ] << mod
385
+ modules[:base_format][format_class] ||= []
386
+ modules[:base_format][format_class] << mod
353
387
  else
354
388
  # ready to include dynamically in set members' format singletons
355
- format_hash = modules[ :nonbase_format ][ format_class ] ||= {}
356
- format_hash[ shortname ] ||= []
357
- format_hash[ shortname ] << mod
389
+ format_hash = modules[:nonbase_format][format_class] ||= {}
390
+ format_hash[shortname] ||= []
391
+ format_hash[shortname] << mod
358
392
  end
359
393
  end
360
394
 
@@ -377,15 +411,18 @@ EOF
377
411
 
378
412
  private
379
413
 
380
-
381
414
  def set_event_callbacks event, opts
382
415
  [:before, :after, :around].each do |kind|
383
- if object_method = opts.delete(kind)
416
+ if (object_method = opts.delete(kind))
384
417
  this_set_module = self
385
418
  Card.class_eval do
386
- set_callback object_method, kind, event, prepend: true, if: proc { |c|
387
- c.singleton_class.include?( this_set_module ) and c.event_applies? opts
388
- }
419
+ set_callback(
420
+ object_method, kind, event,
421
+ prepend: true, if: proc do |c|
422
+ c.singleton_class.include?(this_set_module) &&
423
+ c.event_applies?(opts)
424
+ end
425
+ )
389
426
  end
390
427
  end
391
428
  end
@@ -393,16 +430,16 @@ EOF
393
430
 
394
431
  def get_traits mod
395
432
  Card::Set.traits ||= {}
396
- Card::Set.traits[mod] or Card::Set.traits[mod] = {}
433
+ Card::Set.traits[mod] || Card::Set.traits[mod] = {}
397
434
  end
398
435
 
399
436
  def add_traits args, options
400
437
  mod = self
401
- # raise "Can't define card traits on all set" if mod == Card
438
+ # raise "Can't define card traits on all set" if mod == Card
402
439
  mod_traits = get_traits mod
403
440
 
404
- new_opts = options[:type] ? {type: options[:type]} : {}
405
- new_opts.merge!( {content: options[:default]} ) if options[:default]
441
+ new_opts = options[:type] ? { type: options[:type] } : {}
442
+ new_opts.merge!(content: options[:default]) if options[:default]
406
443
 
407
444
  args.each do |trait|
408
445
  define_trait_card trait, new_opts
@@ -424,7 +461,7 @@ EOF
424
461
  def define_trait_reader trait
425
462
  define_method trait do
426
463
  trait_var "@#{trait}" do
427
- send( "#{trait}_card" ).content
464
+ send("#{trait}_card").content
428
465
  end
429
466
  end
430
467
  end
@@ -432,8 +469,7 @@ EOF
432
469
  def define_trait_writer trait
433
470
  define_method "#{trait}=" do |value|
434
471
  card = send "#{trait}_card"
435
- self.subcards ||= {}
436
- self.subcards[card.name] = {type_id: card.type_id, content: value }
472
+ subcards.add name: card.name, type_id: card.type_id, content: value
437
473
  instance_variable_set "@#{trait}", value
438
474
  end
439
475
  end
@@ -445,10 +481,10 @@ EOF
445
481
 
446
482
  def attachment name, args
447
483
  include Abstract::Attachment
448
- set_specific_attributes name, :load_from_mod, "remote_#{name}_url".to_sym,
484
+ set_specific_attributes name, :load_from_mod, :cached_upload,
485
+ "remote_#{name}_url".to_sym
449
486
  uploader_class = args[:uploader] || FileUploader
450
487
  mount_uploader name, uploader_class
451
488
  end
452
489
  end
453
490
  end
454
-