card-mod-mirror 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []