card-mod-mirror 0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|