card-mod-mirror 0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5e7b9160a101445c73c8c54a068117118904ff0a54347ef666b8f0a5dfdf9ce8
4
+ data.tar.gz: ed3a86a1ad65b17d860d8c08be205b60ac6d78406e3e7582d6694a89a4a498a6
5
+ SHA512:
6
+ metadata.gz: c8d1504824debb0bcb40a696390397c5fa3faa125742abaf6610b1a43af9602ea1f362f48ac95baebb29fbb8648ffffee2c713dfe722eb09571823f967c7ddb2
7
+ data.tar.gz: '0185f499ace9e7efa11bd1c9156b3355d06e01f4b7c12619b3f70f5b7fe8cc8f93a01f6217c2272a165bec9904cdcfc8239f71c949f19a58c49d4dedebc4caaa'
data/README.md ADDED
@@ -0,0 +1,27 @@
1
+ <!--
2
+ # @title README - mod: mirror
3
+ -->
4
+
5
+ # Mirror mod (experimental)
6
+
7
+ This mod supports maintaining two lists – a _Mirror_ list and a _Mirrored_ list
8
+ – that, well, mirror each other. This has sometimes been referred to in Decko
9
+ circles as _bidirectionality_
10
+
11
+ By well-established convention, many card Sharks set up patterns where an
12
+ explicit list (a card whose type is List or Pointer) is used by Searches.
13
+
14
+ For example, imagine you have two cardtypes: `Beans` and `Colors`. You'd like to
15
+ be able to go to a Bean card and see all the Colors for that Bean, OR go to a
16
+ Color and see all the Beans for that Color. If you use the List/Search pattern,
17
+ then one of these is a List and the other is a Search. Say you decide to make it
18
+ so the Bean has a List of colors. Then you will need to make it so that the
19
+ Color cards have a Search for all the bean lists that refer to that color.
20
+
21
+ The problem is that only Lists are directly editable. (If you edit a search,
22
+ then you're editing a query, not directly adding to or subtracting from the
23
+ list).
24
+
25
+ This mod solves that problem by providing two list types that mirror each other.
26
+ Edit one and those changes take effect on the other one.
27
+
@@ -0,0 +1,49 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ def list_fields
4
+ Card.search({ left: name, type_id: MirroredListID }, "list fields")
5
+ end
6
+
7
+ def listed_by_fields
8
+ Card.search({ left: name, type_id: MirrorListID }, "listed by fields")
9
+ end
10
+
11
+ def linker_lists
12
+ Card.search({ type_id: MirroredListID, link_to: name },
13
+ "lists that link to #{name}")
14
+ end
15
+
16
+ def codename_list_exist?
17
+ Card::Codename.exist?(:mirrored_list) && Card::Codename.exist?(:mirror_list)
18
+ end
19
+
20
+ event :trunk_cardtype_of_a_list_relation_changed, :finalize,
21
+ changed: :type, on: :update, when: :codename_list_exist? do
22
+ type_key_was = Card.quick_fetch(type_id_before_act)&.key
23
+
24
+ list_fields.each do |card|
25
+ card.update_listed_by_cache_for card.item_keys, type_key: type_key_was
26
+ card.update_listed_by_cache_for card.item_keys
27
+ end
28
+ listed_by_fields.each &:update_cached_list
29
+ end
30
+
31
+ event :trunk_name_of_a_list_relation_changed, :finalize,
32
+ changed: :name, on: :update,
33
+ when: :codename_list_exist? do
34
+ list_fields.each do |card|
35
+ card.update_listed_by_cache_for card.item_keys
36
+ end
37
+ listed_by_fields.each &:update_cached_list
38
+ end
39
+
40
+ event :cardtype_of_list_item_changed, :validate,
41
+ changed: :type, on: :save,
42
+ when: :codename_list_exist? do
43
+ linker_lists.each do |card|
44
+ next unless card.item_type_id != type_id
45
+ errors.add(:type,
46
+ "can't be changed because #{name} " \
47
+ "is referenced by list card #{card.name}")
48
+ end
49
+ end
@@ -0,0 +1,93 @@
1
+ include_set Abstract::Pointer
2
+
3
+ event :validate_listed_by_name, :validate, on: :save, changing: :name do
4
+ if !compound? || !right || right.type_id != Card::CardtypeID
5
+ errors.add :name, t(:mirror_cardtype_right)
6
+ end
7
+ end
8
+
9
+ event :validate_listed_by_content, :validate,
10
+ on: :save, changing: :content do
11
+ item_cards(content: content).each do |item_card|
12
+ next unless item_card.type_id != right.id
13
+ errors.add(
14
+ :content,
15
+ "#{item_card.name} has wrong cardtype; " \
16
+ "only cards of type #{name.right} are allowed"
17
+ )
18
+ end
19
+ end
20
+
21
+ event :update_content_in_list_cards, :prepare_to_validate,
22
+ on: :save, changing: :content do
23
+ return unless db_content.present?
24
+ new_items = item_keys(content: db_content)
25
+ old_items = item_keys(content: old_content)
26
+ remove_items(old_items - new_items)
27
+ add_items(new_items - old_items)
28
+ end
29
+
30
+ def old_content
31
+ db_content_before_act.present? ? db_content_before_act : content_cache.read(key)
32
+ end
33
+
34
+ def remove_items items
35
+ items.each do |item|
36
+ next unless (lc = list_card item)
37
+ lc.drop_item name.left
38
+ subcards.add lc
39
+ end
40
+ end
41
+
42
+ def add_items items
43
+ items.each do |item|
44
+ if (lc = list_card(item))
45
+ lc.add_item name.left
46
+ subcards.add lc
47
+ else
48
+ subcards.add(name: [item, left.type_name].cardname,
49
+ type: "list",
50
+ content: "[[#{name.left}]]")
51
+ end
52
+ end
53
+ end
54
+
55
+ def content_cache
56
+ Card::Cache[Card::Set::Type::MirrorList]
57
+ end
58
+
59
+ def content
60
+ content_cache.fetch(key) do
61
+ generate_content
62
+ end
63
+ end
64
+
65
+ def generate_content
66
+ listed_by.map do |item|
67
+ "[[%s]]" % item.to_name.left
68
+ end.join "\n"
69
+ end
70
+
71
+ def listed_by
72
+ Card.search(
73
+ { type_id: Card::MirroredListID, right: trunk.type_name,
74
+ left: { type: name.tag }, refer_to: name.trunk, return: :name },
75
+ "all cards listed by #{name}"
76
+ )
77
+ end
78
+
79
+ def update_cached_list
80
+ if trunk
81
+ Card::Cache[Card::Set::Type::MirrorList].write key, generate_content
82
+ else
83
+ Card::Cache[Card::Set::Type::MirrorList].delete key
84
+ end
85
+ end
86
+
87
+ def list_card item
88
+ Card.fetch item, left.type_name
89
+ end
90
+
91
+ def unfilled?
92
+ false
93
+ end
@@ -0,0 +1,110 @@
1
+ include_set Abstract::Pointer
2
+
3
+ event :validate_list_name, :validate, on: :save, changed: :name do
4
+ errors.add :name, t(:mirror_cardtype_right) unless right&.type_id == Card::CardtypeID
5
+ end
6
+
7
+ event :validate_list_item_type_change, :validate,
8
+ on: :save, changed: :name do
9
+ item_cards.each do |item_card|
10
+ next unless item_card.type_name.key != item_type_name.key
11
+ errors.add :name, t(:mirror_conflict_item_type)
12
+ end
13
+ end
14
+
15
+ event :validate_list_content, :validate,
16
+ on: :save, changed: :content do
17
+ item_cards.each do |item_card|
18
+ next unless item_card.type_name.key != item_type_name.key
19
+ errors.add :content, t(
20
+ :mirror_only_type_allowed,
21
+ cardname: item_card.name,
22
+ cardtype: name.right
23
+ )
24
+ end
25
+ end
26
+
27
+ event :create_listed_by_cards, :prepare_to_validate,
28
+ on: :save, changed: :content do
29
+ item_names.each do |item_name|
30
+ listed_by_name = "#{item_name}+#{left.type_name}"
31
+ next if director.main_director.card.key == listed_by_name.to_name.key
32
+ if !Card[listed_by_name]
33
+ add_subcard listed_by_name, type_id: Card::MirrorListID
34
+ else
35
+ Card[listed_by_name].update_references_out
36
+ end
37
+ end
38
+ end
39
+
40
+ event :update_related_listed_by_card_on_create, :finalize, on: :create do
41
+ update_listed_by_cache_for item_keys
42
+ end
43
+
44
+ event :update_related_listed_by_card_on_content_update, :finalize,
45
+ on: :update, changed: :content do
46
+ new_items = item_keys
47
+ changed_items =
48
+ if db_content_before_act
49
+ old_items = item_keys(content: db_content_before_act)
50
+ old_items + new_items - (old_items & new_items)
51
+ else
52
+ new_items
53
+ end
54
+ update_listed_by_cache_for changed_items
55
+ end
56
+
57
+ event :update_related_listed_by_card_on_name_and_type_changes, :finalize,
58
+ on: :update, changed: %i[name type_id] do
59
+ update_all_items
60
+ end
61
+
62
+ event :update_related_listed_by_card_on_delete, :finalize,
63
+ on: :delete, when: :compound? do
64
+ update_listed_by_cache_for item_keys, type_key: @left_type_key
65
+ end
66
+
67
+ event :cache_type_key, :store, on: :delete, when: :compound? do
68
+ @left_type_key = left.type_card.key
69
+ end
70
+
71
+ def update_all_items
72
+ current_items = item_keys
73
+ if db_content_before_act
74
+ old_items = item_keys(content: db_content_before_act)
75
+ update_listed_by_cache_for old_items
76
+ end
77
+ update_listed_by_cache_for current_items
78
+ end
79
+
80
+ def update_listed_by_cache_for item_keys, args={}
81
+ type_key = args[:type_key] || left&.type_card&.key
82
+ return unless type_key
83
+
84
+ item_keys.each do |item_key|
85
+ key = "#{item_key}+#{type_key}"
86
+ next unless Card::Cache[Card::Set::Type::MirrorList].exist? key
87
+ if (card = Card.fetch(key)) && card.left
88
+ card.update_cached_list
89
+ card.update_references_out
90
+ else
91
+ Card::Cache[Card::Set::Type::MirrorList].delete key
92
+ end
93
+ end
94
+ end
95
+
96
+ def item_type
97
+ name.right
98
+ end
99
+
100
+ def item_type_name
101
+ name.right_name
102
+ end
103
+
104
+ def item_type_card
105
+ name.right
106
+ end
107
+
108
+ def item_type_id
109
+ right.id
110
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: card-mod-mirror
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ platform: ruby
6
+ authors:
7
+ - Philipp Kühl
8
+ - Ethan McCutchen
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2021-10-26 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: card
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ description: ''
29
+ email:
30
+ - info@decko.org
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - README.md
36
+ - set/all/list_changes.rb
37
+ - set/type/mirror_list.rb
38
+ - set/type/mirrored_list.rb
39
+ homepage: http://decko.org
40
+ licenses:
41
+ - GPL-3.0
42
+ metadata:
43
+ card-mod: mirror
44
+ post_install_message:
45
+ rdoc_options: []
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '2.5'
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubygems_version: 3.2.28
60
+ signing_key:
61
+ specification_version: 4
62
+ summary: mirror
63
+ test_files: []