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 +7 -0
- data/README.md +27 -0
- data/set/all/list_changes.rb +49 -0
- data/set/type/mirror_list.rb +93 -0
- data/set/type/mirrored_list.rb +110 -0
- metadata +63 -0
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: []
|