card 1.19.1 → 1.19.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +3 -3
- data/VERSION +1 -1
- data/db/migrate_core_cards/20160908154210_add_trash_card.rb +7 -0
- data/lib/card.rb +2 -2
- data/lib/card/act_manager.rb +143 -0
- data/lib/card/act_manager/stage.rb +56 -0
- data/lib/card/act_manager/stage_director.rb +313 -0
- data/lib/card/act_manager/subdirector_array.rb +43 -0
- data/lib/card/set.rb +1 -0
- data/lib/card/set/i18n_scope.rb +52 -0
- data/lib/card/subcards.rb +2 -3
- data/lib/cardio.rb +4 -4
- data/mod/admin/set/self/admin.rb +1 -2
- data/mod/admin/set/self/trash.rb +29 -0
- data/mod/core/set/abstract/code_file.rb +5 -25
- data/mod/core/set/all/actify.rb +35 -0
- data/mod/core/set/all/fetch.rb +12 -15
- data/mod/core/set/all/i18n.rb +9 -0
- data/mod/core/set/all/phases.rb +1 -1
- data/mod/core/set/all/stages.rb +2 -2
- data/mod/developer/set/all/event_viz.rb +2 -1
- data/mod/email/set/all/notify.rb +1 -1
- data/mod/history/lib/card/act.rb +1 -1
- data/mod/history/lib/card/action.rb +1 -1
- data/mod/history/set/all/history.rb +1 -1
- data/mod/machines/set/abstract/machine.rb +1 -1
- data/mod/machines/spec/set/type/coffeescript_spec.rb +1 -1
- data/mod/machines/spec/set/type/css_spec.rb +1 -1
- data/mod/machines/spec/set/type/javascript_spec.rb +1 -1
- data/mod/machines/spec/set/type/scss_spec.rb +1 -1
- data/mod/machines/spec/set/type/skin_spec.rb +1 -1
- data/mod/machines/spec/{lib/shared_machine_examples.rb → shared_examples/machine.rb} +15 -24
- data/mod/machines/spec/{lib/shared_machine_input_examples.rb → shared_examples/machine_input.rb} +0 -0
- data/mod/settings/spec/set/right/script_spec.rb +1 -1
- data/mod/settings/spec/set/right/style_spec.rb +1 -4
- data/mod/solid_cache/set/abstract/solid_cache.rb +1 -1
- data/spec/lib/card/content_spec.rb +118 -132
- data/spec/lib/card/i18n_spec.rb +6 -7
- data/spec/lib/card/query_spec.rb +5 -4
- data/spec/lib/card/stage_director_spec.rb +1 -1
- data/spec/spec_helper.rb +3 -4
- data/tmpsets/set/{mod002-core → mod001-core}/abstract/code_file.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/actify.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/active_card.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/collection.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/content.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/erb.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/event.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/export.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/fetch.rb +12 -14
- data/tmpsets/set/{mod002-core → mod001-core}/all/haml.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/initialize.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/location_history.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/name.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/name_validations.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/pattern.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/permissions.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/phases.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/references.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/rules.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/stages.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/states.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/subcards.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/templating.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/tracked_attributes.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/trash.rb +0 -50
- data/tmpsets/set/{mod002-core → mod001-core}/all/type.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/utils.rb +33 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/view_cache.rb +0 -0
- data/tmpsets/set/{mod003-history → mod002-history}/all/actions.rb +0 -0
- data/tmpsets/set/{mod003-history → mod002-history}/all/content_history.rb +0 -0
- data/tmpsets/set/{mod003-history → mod002-history}/all/history.rb +0 -0
- data/tmpsets/set/{mod004-basic_formats → mod003-basic_formats}/all/all_css.rb +0 -0
- data/tmpsets/set/{mod004-basic_formats → mod003-basic_formats}/all/all_csv.rb +0 -0
- data/tmpsets/set/{mod004-basic_formats → mod003-basic_formats}/all/all_js.rb +0 -0
- data/tmpsets/set/{mod004-basic_formats → mod003-basic_formats}/all/base.rb +0 -0
- data/tmpsets/set/{mod004-basic_formats → mod003-basic_formats}/all/file.rb +0 -0
- data/tmpsets/set/{mod004-basic_formats → mod003-basic_formats}/all/json.rb +0 -0
- data/tmpsets/set/{mod004-basic_formats → mod003-basic_formats}/all/rss.rb +0 -0
- data/tmpsets/set/{mod004-basic_formats → mod003-basic_formats}/all/text.rb +0 -0
- data/tmpsets/set/{mod004-basic_formats → mod003-basic_formats}/self/01_head/javascript.rb +0 -0
- data/tmpsets/set/{mod004-basic_formats → mod003-basic_formats}/self/head.rb +1 -1
- data/tmpsets/set/{mod005-pointer → mod004-pointer}/abstract/01_pointer.rb +0 -0
- data/tmpsets/set/{mod005-pointer → mod004-pointer}/abstract/01_pointer/edit.rb +0 -0
- data/tmpsets/set/{mod005-pointer → mod004-pointer}/abstract/code_pointer.rb +0 -0
- data/tmpsets/set/{mod005-pointer → mod004-pointer}/self/script_editors.rb +0 -0
- data/tmpsets/set/{mod005-pointer → mod004-pointer}/self/script_mods.rb +0 -0
- data/tmpsets/set/{mod005-pointer → mod004-pointer}/self/script_pointer_config.rb +0 -0
- data/tmpsets/set/{mod005-pointer → mod004-pointer}/type/pointer.rb +0 -0
- data/tmpsets/set/{mod006-ace_editor → mod005-ace_editor}/abstract/ace_editor.rb +0 -0
- data/tmpsets/set/{mod006-ace_editor → mod005-ace_editor}/self/script_ace.rb +0 -0
- data/tmpsets/set/{mod006-ace_editor → mod005-ace_editor}/self/script_ace_config.rb +0 -0
- data/tmpsets/set/{mod007-prosemirror_editor → mod006-prosemirror_editor}/abstract/prosemirror_editor.rb +0 -0
- data/tmpsets/set/{mod007-prosemirror_editor → mod006-prosemirror_editor}/self/script_prosemirror.rb +0 -0
- data/tmpsets/set/{mod007-prosemirror_editor → mod006-prosemirror_editor}/self/script_prosemirror_config.rb +0 -0
- data/tmpsets/set/{mod009-solid_cache → mod008-solid_cache}/abstract/solid_cache.rb +1 -1
- data/tmpsets/set/{mod009-solid_cache → mod008-solid_cache}/all/solid_cache.rb +0 -0
- data/tmpsets/set/{mod009-solid_cache → mod008-solid_cache}/right/solid_cache.rb +0 -0
- data/tmpsets/set/{mod010-basic_types → mod009-basic_types}/type/html.rb +0 -0
- data/tmpsets/set/{mod010-basic_types → mod009-basic_types}/type/plain_text.rb +0 -0
- data/tmpsets/set/{mod011-machines → mod010-machines}/abstract/script.rb +0 -0
- data/tmpsets/set/{mod011-machines → mod010-machines}/all/reset_machines.rb +0 -0
- data/tmpsets/set/{mod011-machines → mod010-machines}/right/machine_cache.rb +0 -0
- data/tmpsets/set/{mod011-machines → mod010-machines}/right/machine_input.rb +0 -0
- data/tmpsets/set/{mod011-machines → mod010-machines}/right/machine_output.rb +1 -9
- data/tmpsets/set/{mod011-machines → mod010-machines}/self/script_card_menu.rb +0 -0
- data/tmpsets/set/{mod011-machines → mod010-machines}/self/script_html5shiv_printshiv.rb +0 -0
- data/tmpsets/set/{mod011-machines → mod010-machines}/self/script_jquery.rb +0 -0
- data/tmpsets/set/{mod011-machines → mod010-machines}/self/script_jquery_helper.rb +0 -0
- data/tmpsets/set/{mod011-machines → mod010-machines}/self/script_slot.rb +0 -0
- data/tmpsets/set/{mod011-machines → mod010-machines}/self/style_bootstrap_compatible.rb +0 -0
- data/tmpsets/set/{mod011-machines → mod010-machines}/self/style_cards.rb +0 -0
- data/tmpsets/set/{mod011-machines → mod010-machines}/self/style_jquery_ui_smoothness.rb +0 -0
- data/tmpsets/set/{mod011-machines → mod010-machines}/type/coffee_script.rb +6 -2
- data/tmpsets/set/{mod011-machines → mod010-machines}/type/css.rb +2 -2
- data/tmpsets/set/{mod011-machines → mod010-machines}/type/java_script.rb +2 -2
- data/tmpsets/set/{mod011-machines → mod010-machines}/type/scss.rb +0 -0
- data/tmpsets/set/{mod011-machines → mod010-machines}/type/skin.rb +2 -2
- data/tmpsets/set/{mod012-settings → mod011-settings}/abstract/permission.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/right/add_help.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/right/comment.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/right/create.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/right/default.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/right/delete.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/right/help.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/right/read.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/right/script.rb +1 -1
- data/tmpsets/set/{mod012-settings → mod011-settings}/right/structure.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/right/style.rb +1 -1
- data/tmpsets/set/{mod012-settings → mod011-settings}/right/update.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/accountable.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/add_help.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/autoname.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/captcha.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/create.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/default.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/default_html_view.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/delete.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/follow_fields.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/help.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/input.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/layout.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/on_create.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/on_delete.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/on_update.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/options.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/options_label.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/read.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/recent_settings.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/script.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/structure.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/style.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/table_of_contents.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/thanks.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/update.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/type/setting.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/all/email_html.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/all/email_text.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/all/follow.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/all/notify.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/all/observer.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/right/bcc.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/right/cc.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/right/follow.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/right/follow_fields.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/right/followers.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/right/following.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/right/from.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/right/html_message.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/right/to.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/self/always.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/self/created.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/self/edited.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/self/follow.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/self/follow_defaults.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/self/never.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/type/email_template.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/type_plus_right/user/follow.rb +8 -4
- data/tmpsets/set/mod016-standard/all/links.rb +2 -2
- data/tmpsets/set/mod018-bootstrap/all/bootstrap/table.rb +1 -1
- data/tmpsets/set/mod018-bootstrap/self/bootswatch_shared.rb +1 -1
- metadata +149 -163
- data/lib/card/director_register.rb +0 -101
- data/lib/card/stage.rb +0 -106
- data/lib/card/stage_director.rb +0 -310
- data/lib/card/subdirector_array.rb +0 -43
- data/tmpsets/set/mod001-admin/self/admin.rb +0 -130
- data/tmpsets/set/mod001-admin/self/admin_info.rb +0 -110
- data/tmpsets/set/mod001-admin/self/version.rb +0 -15
- data/tmpsets/set/mod002-core/all/debug.rb +0 -30
- data/tmpsets/set/mod002-core/all/update_read_rules.rb +0 -91
- data/tmpsets/set/mod011-machines/abstract/machine.rb +0 -277
- data/tmpsets/set/mod011-machines/abstract/machine_input.rb +0 -83
- data/tmpsets/set/mod014-developer/all/event_viz.rb +0 -59
- data/tmpsets/set/mod014-developer/all/view_viz.rb +0 -30
- data/tmpsets/set/mod014-developer/right/debug.rb +0 -96
- data/tmpsets/set/mod015-carrierwave/abstract/attachment.rb +0 -118
- data/tmpsets/set/mod015-carrierwave/abstract/attachment/paths.rb +0 -57
- data/tmpsets/set/mod015-carrierwave/abstract/attachment/storage_type.rb +0 -326
- data/tmpsets/set/mod015-carrierwave/abstract/attachment/upload_cache.rb +0 -84
- data/tmpsets/set/mod015-carrierwave/all/file_utils.rb +0 -35
- data/tmpsets/set/mod015-carrierwave/self/admin.rb +0 -30
- data/tmpsets/set/mod015-carrierwave/type/file.rb +0 -158
- data/tmpsets/set/mod015-carrierwave/type/image.rb +0 -97
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c530f9f078a90e9de4c239d7f5222e670b10b98a
|
4
|
+
data.tar.gz: 735604a8c31fe1247d23e3bbc5c90d495c83593a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 43e1f744865904f81aec258a25a0f823693b2b8b418491e451594a18f345fb4b79e796ece4ca46e4c9ac604c9622646faf137801353348802d7b5c790d14e270
|
7
|
+
data.tar.gz: 6224a80edc261e7b8636dce40fdb1357ee1d94e08c4fc32208587f6470b413c4e3af370156bfb1d9553159a5872245cc10cf1fb304d94d7413d50da90c8a4969
|
data/.yardopts
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.19.
|
1
|
+
1.19.2
|
data/lib/card.rb
CHANGED
@@ -42,8 +42,8 @@ class Card < ActiveRecord::Base
|
|
42
42
|
require_dependency "card/reference"
|
43
43
|
require_dependency "card/subcards"
|
44
44
|
require_dependency "card/cache/view_cache"
|
45
|
-
require_dependency "card/
|
46
|
-
require_dependency "card/
|
45
|
+
require_dependency "card/act_manager"
|
46
|
+
require_dependency "card/act_manager/stage_director"
|
47
47
|
|
48
48
|
has_many :references_in, class_name: :Reference, foreign_key: :referee_id
|
49
49
|
has_many :references_out, class_name: :Reference, foreign_key: :referer_id
|
@@ -0,0 +1,143 @@
|
|
1
|
+
class Card
|
2
|
+
# Manages the whole process of creating an {act Card::Act} ie. changing
|
3
|
+
# a card and attached subcards.
|
4
|
+
#
|
5
|
+
# For every card that is part of the act the ActManager creates a
|
6
|
+
# {StageDirector} that leads the card through all the stages.
|
7
|
+
# Because cards sometimes get expired and reloaded during an act we need
|
8
|
+
# this global object to ensure that the stage information doesn't get lost
|
9
|
+
# until the act is finished.
|
10
|
+
#
|
11
|
+
# The process of creating an act/writing a card change to the database
|
12
|
+
# is divided into 8 stages that are grouped in 3 phases.
|
13
|
+
#
|
14
|
+
# 'validation phase'
|
15
|
+
# * initialize stage (I)
|
16
|
+
# * prepare_to_validate stage (P2V)
|
17
|
+
# * validate stage (V)
|
18
|
+
#
|
19
|
+
# 'storage phase'
|
20
|
+
# * prepare_to_store stage (P2S)
|
21
|
+
# * store stage (S)
|
22
|
+
# * finalize stage (F)
|
23
|
+
#
|
24
|
+
# 'integration phase'
|
25
|
+
# * integrate stage (IG)
|
26
|
+
# * integrate_with_delay stage (IGwD)
|
27
|
+
#
|
28
|
+
#
|
29
|
+
# The table below gives you an overview what you can do in which stage:
|
30
|
+
#
|
31
|
+
# validation | storage | integration
|
32
|
+
# I P2V V | P2S S F | IG IGwD
|
33
|
+
#-------------------------------------------------------------------------
|
34
|
+
# attach subcard yes! yes! yes | yes yes yes | yes
|
35
|
+
# detach subcard yes! yes! yes | yes no no! | no!
|
36
|
+
# validate yes yes yes! | no | no
|
37
|
+
# 1 insecure change yes yes! no | no! | no!
|
38
|
+
# 2 secure change yes | yes! no! no! | no!
|
39
|
+
# abort yes! | yes | yes?
|
40
|
+
# add errors yes! | no! | no!
|
41
|
+
# 3 create other cards yes | yes | yes
|
42
|
+
# has id no | no no? yes | yes
|
43
|
+
# within web request yes | yes | yes no
|
44
|
+
# 4 within transaction yes | yes | no
|
45
|
+
|
46
|
+
# available values:
|
47
|
+
# dirty attributes yes | yes | yes
|
48
|
+
# params yes | yes | yes
|
49
|
+
# success yes | yes | yes no
|
50
|
+
# session yes | yes | yes no
|
51
|
+
#
|
52
|
+
#
|
53
|
+
# Explanation:
|
54
|
+
# yes! the recommended stage to do that
|
55
|
+
# yes ok to do it here
|
56
|
+
# no not recommended; chance to mess things up
|
57
|
+
# but if something forces you to do it here you can try
|
58
|
+
# no! never do it here. it won't work or will break things
|
59
|
+
#
|
60
|
+
# if there is only a single entry in a phase column it counts for all stages
|
61
|
+
# of that phase
|
62
|
+
#
|
63
|
+
# 1) 'insecure' means a change of a card attribute that can possibly make
|
64
|
+
# the card invalid to save
|
65
|
+
# 2) 'secure' means you are sure that the change doesn't affect the validation
|
66
|
+
# 3) If you call 'create', 'update_attributes' or 'save' the card will become
|
67
|
+
# part of the same act and all stage of the validation and storage phase
|
68
|
+
# will be executed immediately for that card. The integration phase will be
|
69
|
+
# executed together with the act card and its subcards
|
70
|
+
# 4) This means if an exception is raised in the validation or storage phase
|
71
|
+
# everything will rollback. If the integration phase fails the db changes
|
72
|
+
# of the other two phases will remain persistent.
|
73
|
+
class ActManager
|
74
|
+
cattr_accessor :act_card
|
75
|
+
|
76
|
+
class << self
|
77
|
+
def act_director
|
78
|
+
return unless act_card
|
79
|
+
act_card.director
|
80
|
+
end
|
81
|
+
|
82
|
+
def directors
|
83
|
+
@directors ||= {}
|
84
|
+
end
|
85
|
+
|
86
|
+
def clear
|
87
|
+
ActManager.act_card = nil
|
88
|
+
directors.each_pair do |card, _dir|
|
89
|
+
card.director = nil
|
90
|
+
end
|
91
|
+
@directors = nil
|
92
|
+
end
|
93
|
+
|
94
|
+
def fetch card, opts={}
|
95
|
+
return directors[card] if directors[card]
|
96
|
+
directors.each_key do |dir_card|
|
97
|
+
return dir_card.director if dir_card.name == card.name
|
98
|
+
end
|
99
|
+
directors[card] = new_director card, opts
|
100
|
+
end
|
101
|
+
|
102
|
+
def new_director card, opts={}
|
103
|
+
if opts[:parent]
|
104
|
+
StageSubdirector.new card, opts
|
105
|
+
elsif act_card && act_card != card && running_act?
|
106
|
+
act_card.director.subdirectors.add card
|
107
|
+
else
|
108
|
+
StageDirector.new card
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def add director
|
113
|
+
directors[director.card] = director
|
114
|
+
end
|
115
|
+
|
116
|
+
def card_changed old_card
|
117
|
+
return unless (director = @directors.delete old_card)
|
118
|
+
add director
|
119
|
+
end
|
120
|
+
|
121
|
+
def delete director
|
122
|
+
return unless @directors
|
123
|
+
@directors.delete director.card
|
124
|
+
director.delete
|
125
|
+
end
|
126
|
+
|
127
|
+
def deep_delete director
|
128
|
+
director.subdirectors.each do |subdir|
|
129
|
+
deep_delete subdir
|
130
|
+
end
|
131
|
+
delete director
|
132
|
+
end
|
133
|
+
|
134
|
+
def running_act?
|
135
|
+
(dir = act_director) && dir.running?
|
136
|
+
end
|
137
|
+
|
138
|
+
def to_s
|
139
|
+
directors.values.map(&:to_s).join "\n"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
class Card
|
2
|
+
class ActManager
|
3
|
+
module Stage
|
4
|
+
STAGES = [:initialize, :prepare_to_validate, :validate, :prepare_to_store,
|
5
|
+
:store, :finalize, :integrate, :integrate_with_delay].freeze
|
6
|
+
stage_index = {}
|
7
|
+
STAGES.each_with_index do |stage, i|
|
8
|
+
stage_index[stage] = i
|
9
|
+
end
|
10
|
+
STAGE_INDEX = stage_index.freeze
|
11
|
+
|
12
|
+
def stage_symbol index
|
13
|
+
case index
|
14
|
+
when Symbol
|
15
|
+
return index if STAGE_INDEX[index]
|
16
|
+
when Integer
|
17
|
+
return STAGES[index] if index < STAGES.size
|
18
|
+
end
|
19
|
+
raise Card::Error, "not a valid stage index: #{index}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def stage_index stage
|
23
|
+
case stage
|
24
|
+
when Symbol then
|
25
|
+
return STAGE_INDEX[stage]
|
26
|
+
when Integer then
|
27
|
+
return stage
|
28
|
+
else
|
29
|
+
raise Card::Error, "not a valid stage: #{stage}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def stage_ok? opts
|
34
|
+
stage && (
|
35
|
+
(opts[:during] && in?(opts[:during])) ||
|
36
|
+
(opts[:before] && before?(opts[:before])) ||
|
37
|
+
(opts[:after] && after?(opts[:after])) ||
|
38
|
+
true # no phase restriction in opts
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
def before? allowed_phase
|
43
|
+
STAGE_INDEX[allowed_phase] > STAGE_INDEX[stage]
|
44
|
+
end
|
45
|
+
|
46
|
+
def after? allowed_phase
|
47
|
+
STAGE_INDEX[allowed_phase] < STAGE_INDEX[stage]
|
48
|
+
end
|
49
|
+
|
50
|
+
def in? allowed_phase
|
51
|
+
(allowed_phase.is_a?(Array) && allowed_phase.include?(stage)) ||
|
52
|
+
allowed_phase == stage
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,313 @@
|
|
1
|
+
|
2
|
+
class Card
|
3
|
+
def restore_changes_information
|
4
|
+
return unless @previously_changed
|
5
|
+
@changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
|
6
|
+
@previously_changed.each do |k, (old, _new)|
|
7
|
+
@changed_attributes[k] = old
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def clean_after_stage_fail
|
12
|
+
@action = nil
|
13
|
+
expire_pieces
|
14
|
+
subcards.each(&:expire_pieces)
|
15
|
+
end
|
16
|
+
|
17
|
+
class ActManager
|
18
|
+
# A 'StageDirector' executes the stages of a card when the card gets
|
19
|
+
# created, updated or deleted.
|
20
|
+
# For subcards, i.e. other cards that are changed in the same act, a
|
21
|
+
# StageDirector has StageSubdirectors that take care of the stages for
|
22
|
+
# those cards
|
23
|
+
#
|
24
|
+
# In general a stage is executed for all involved cards before the
|
25
|
+
# StageDirector proceeds with the next stage.
|
26
|
+
# Only exception is the finalize stage.
|
27
|
+
# The finalize stage of a subcard is executed immediately after its store
|
28
|
+
# stage. When all subcards are finalized the supercard's finalize stage is
|
29
|
+
# executed.
|
30
|
+
#
|
31
|
+
# If a subcard is added in a stage then it catches up at the end of the
|
32
|
+
# stage to the current stage.
|
33
|
+
# For example if you add a subcard in a card's :prepare_to_store stage then
|
34
|
+
# after that stage the stages :initialize, :prepare_to_validate,
|
35
|
+
# :validate and :prepare_to_store are executed for the subcard.
|
36
|
+
#
|
37
|
+
# Stages are executed with pre-order depth-first search.
|
38
|
+
# That means if A has subcards AA and AB; AAA is subcard of AA and ABA
|
39
|
+
# subcard of AB then the order of execution is
|
40
|
+
# A -> AA -> AAA -> AB -> ABA
|
41
|
+
#
|
42
|
+
# A special case can happen in the store phase.
|
43
|
+
# If the id of a subcard is needed for a supercard
|
44
|
+
# (for example as left_id or as type_id) and the subcard doesn't
|
45
|
+
# have an id yet (because it gets created in the same act)
|
46
|
+
# then the subcard's store stage is executed before the supercard's store
|
47
|
+
# stage
|
48
|
+
class StageDirector
|
49
|
+
include Stage
|
50
|
+
|
51
|
+
attr_accessor :prior_store, :act, :card, :stage, :parent, :main,
|
52
|
+
:subdirectors, :transact_in_stage
|
53
|
+
attr_reader :running
|
54
|
+
alias_method :running?, :running
|
55
|
+
alias_method :main?, :main
|
56
|
+
|
57
|
+
def initialize card, opts={}, main=true
|
58
|
+
@card = card
|
59
|
+
@card.director = self
|
60
|
+
# for read actions there is no validation phase
|
61
|
+
# so we have to set the action here
|
62
|
+
@card.identify_action
|
63
|
+
|
64
|
+
@stage = nil
|
65
|
+
@running = false
|
66
|
+
@prepared = false
|
67
|
+
@parent = opts[:parent]
|
68
|
+
# has card to be stored before the supercard?
|
69
|
+
@prior_store = opts[:priority]
|
70
|
+
@call_after_store = []
|
71
|
+
@main = main
|
72
|
+
@subdirectors = SubdirectorArray.initialize_with_subcards(self)
|
73
|
+
register
|
74
|
+
end
|
75
|
+
|
76
|
+
def register
|
77
|
+
ActManager.add self
|
78
|
+
end
|
79
|
+
|
80
|
+
def unregister
|
81
|
+
ActManager.delete self
|
82
|
+
end
|
83
|
+
|
84
|
+
def delete
|
85
|
+
@card.director = nil
|
86
|
+
@subdirectors.clear
|
87
|
+
@stage = nil
|
88
|
+
@action = nil
|
89
|
+
end
|
90
|
+
|
91
|
+
def prepare_for_phases
|
92
|
+
@card.prepare_for_phases unless @prepared
|
93
|
+
@prepared = true
|
94
|
+
@subdirectors.each(&:prepare_for_phases)
|
95
|
+
end
|
96
|
+
|
97
|
+
def validation_phase
|
98
|
+
run_single_stage :initialize
|
99
|
+
run_single_stage :prepare_to_validate
|
100
|
+
run_single_stage :validate
|
101
|
+
@card.expire_pieces if @card.errors.any?
|
102
|
+
@card.errors.empty?
|
103
|
+
end
|
104
|
+
|
105
|
+
def storage_phase &block
|
106
|
+
catch_up_to_stage :prepare_to_store
|
107
|
+
run_single_stage :store, &block
|
108
|
+
run_single_stage :finalize
|
109
|
+
ensure
|
110
|
+
@from_trash = nil
|
111
|
+
end
|
112
|
+
|
113
|
+
def integration_phase
|
114
|
+
return if @abort
|
115
|
+
@card.restore_changes_information
|
116
|
+
run_single_stage :integrate
|
117
|
+
run_single_stage :integrate_with_delay
|
118
|
+
rescue => e # don't rollback
|
119
|
+
Card::Error.current = e
|
120
|
+
@card.notable_exception_raised
|
121
|
+
return false
|
122
|
+
ensure
|
123
|
+
@card.changes_applied unless @abort
|
124
|
+
ActManager.clear if main? && !@card.only_storage_phase
|
125
|
+
end
|
126
|
+
|
127
|
+
def catch_up_to_stage next_stage
|
128
|
+
if @transact_in_stage
|
129
|
+
return if @transact_in_stage != next_stage
|
130
|
+
next_stage = :integrate_with_delay
|
131
|
+
end
|
132
|
+
upto_stage(next_stage) do |stage|
|
133
|
+
run_single_stage stage
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def reset_stage
|
138
|
+
@stage = -1
|
139
|
+
end
|
140
|
+
|
141
|
+
def abort
|
142
|
+
@abort = true
|
143
|
+
end
|
144
|
+
|
145
|
+
def call_after_store &block
|
146
|
+
@call_after_store << block
|
147
|
+
end
|
148
|
+
|
149
|
+
def need_act
|
150
|
+
act_director = main_director
|
151
|
+
unless act_director
|
152
|
+
raise Card::Error, "act requested without a main stage director"
|
153
|
+
end
|
154
|
+
act_director.act ||= Card::Act.create(ip_address: Env.ip)
|
155
|
+
@card.current_act = @act = act_director.act
|
156
|
+
end
|
157
|
+
|
158
|
+
def main_director
|
159
|
+
if main?
|
160
|
+
self
|
161
|
+
else
|
162
|
+
ActManager.act_director || (@parent && @parent.main_director)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def to_s
|
167
|
+
str = @card.name.to_s.clone
|
168
|
+
if @subdirectors
|
169
|
+
subs = subdirectors.map(&:card)
|
170
|
+
.map { |card| " #{card.name}" }.join "\n"
|
171
|
+
str << "\n#{subs}"
|
172
|
+
end
|
173
|
+
str
|
174
|
+
end
|
175
|
+
|
176
|
+
def update_card card
|
177
|
+
old_card = @card
|
178
|
+
@card = card
|
179
|
+
ActManager.card_changed old_card
|
180
|
+
end
|
181
|
+
|
182
|
+
private
|
183
|
+
|
184
|
+
def upto_stage stage
|
185
|
+
@stage ||= -1
|
186
|
+
(@stage + 1).upto(stage_index(stage)) do |i|
|
187
|
+
yield stage_symbol(i)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def valid_next_stage? stage
|
192
|
+
new_stage = stage_index(stage)
|
193
|
+
@stage ||= -1
|
194
|
+
return if @stage >= new_stage
|
195
|
+
if @stage < new_stage - 1
|
196
|
+
raise Card::Error, "stage #{stage_symbol(new_stage - 1)} was " \
|
197
|
+
"skipped for card #{@card}"
|
198
|
+
end
|
199
|
+
@card.errors.empty? || new_stage > stage_index(:validate)
|
200
|
+
end
|
201
|
+
|
202
|
+
def run_single_stage stage, &block
|
203
|
+
return true unless valid_next_stage? stage
|
204
|
+
# puts "#{@card.name}: #{stage} stage".red
|
205
|
+
|
206
|
+
@stage = stage_index stage
|
207
|
+
if stage == :initialize
|
208
|
+
@running ||= true
|
209
|
+
prepare_for_phases
|
210
|
+
end
|
211
|
+
# in the store stage it can be necessary that
|
212
|
+
# other subcards must be saved before we save this card
|
213
|
+
if stage == :store
|
214
|
+
store(&block)
|
215
|
+
else
|
216
|
+
run_stage_callbacks stage
|
217
|
+
run_subdirector_stages stage
|
218
|
+
end
|
219
|
+
rescue => e
|
220
|
+
@card.clean_after_stage_fail
|
221
|
+
raise e
|
222
|
+
end
|
223
|
+
|
224
|
+
def run_stage_callbacks stage
|
225
|
+
Rails.logger.debug "#{stage}: #{@card.name}"
|
226
|
+
# we use abort :success in the :store stage for :save_draft
|
227
|
+
if stage_index(stage) <= stage_index(:store) && !main?
|
228
|
+
@card.abortable do
|
229
|
+
@card.run_callbacks :"#{stage}_stage"
|
230
|
+
end
|
231
|
+
else
|
232
|
+
@card.run_callbacks :"#{stage}_stage"
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def run_subdirector_stages stage
|
237
|
+
@subdirectors.each do |subdir|
|
238
|
+
subdir.catch_up_to_stage stage
|
239
|
+
end
|
240
|
+
ensure
|
241
|
+
@card.handle_subcard_errors
|
242
|
+
end
|
243
|
+
|
244
|
+
# handle the store stage
|
245
|
+
# The tricky part here is to preserve the dirty marks on the subcards'
|
246
|
+
# attributes for the finalize stage.
|
247
|
+
# To achieve this we can't just call the :store and :finalize callbacks on
|
248
|
+
# the subcards as we do in the other phases.
|
249
|
+
# Instead we have to call `save` on the subcards
|
250
|
+
# and use the ActiveRecord :around_save callback to run the :store and
|
251
|
+
# :finalize stages
|
252
|
+
def store &save_block
|
253
|
+
if main? && !block_given?
|
254
|
+
raise Card::Error, "need block to store main card"
|
255
|
+
end
|
256
|
+
# the block is the ActiveRecord block from the around save callback that
|
257
|
+
# saves the card
|
258
|
+
if block_given?
|
259
|
+
run_stage_callbacks :store
|
260
|
+
store_with_subcards(&save_block)
|
261
|
+
else
|
262
|
+
trigger_storage_phase_callback
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
def store_with_subcards
|
267
|
+
store_pre_subcards
|
268
|
+
yield
|
269
|
+
@call_after_store.each { |handle_id| handle_id.call(@card.id) }
|
270
|
+
store_post_subcards
|
271
|
+
true.tap { @virtual = false } # TODO: find a better place for this
|
272
|
+
ensure
|
273
|
+
@card.handle_subcard_errors
|
274
|
+
end
|
275
|
+
|
276
|
+
# store subcards whose ids we need for this card
|
277
|
+
def store_pre_subcards
|
278
|
+
@subdirectors.each do |subdir|
|
279
|
+
next unless subdir.prior_store
|
280
|
+
subdir.catch_up_to_stage :store
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
def store_post_subcards
|
285
|
+
@subdirectors.each do |subdir|
|
286
|
+
next if subdir.prior_store
|
287
|
+
subdir.catch_up_to_stage :store
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
# trigger the storage_phase, skip the other phases
|
292
|
+
# At this point the :prepare_to_store stage was already executed
|
293
|
+
# by the parent director. So the storage phase will only run
|
294
|
+
# the :store stage and the :finalize stage
|
295
|
+
def trigger_storage_phase_callback
|
296
|
+
@stage = stage_index :prepare_to_store
|
297
|
+
@card.only_storage_phase = true
|
298
|
+
@card.save! validate: false
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
class StageSubdirector < StageDirector
|
303
|
+
def initialize card, opts={}
|
304
|
+
super card, opts, false
|
305
|
+
end
|
306
|
+
|
307
|
+
def delete
|
308
|
+
@parent.subdirectors.delete self if @parent
|
309
|
+
super
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|