card 1.101.0 → 1.101.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 +4 -4
- data/VERSION +1 -1
- data/config/locales/en.yml +9 -6
- data/db/migrate_core_cards/data/decko_logo.svg +1 -59
- data/lib/card.rb +3 -0
- data/lib/card/content/diff/result.rb +40 -29
- data/lib/card/env.rb +2 -2
- data/lib/card/model/save_helper.rb +16 -182
- data/lib/card/model/save_helper/save_arguments.rb +94 -0
- data/lib/card/model/save_helper/save_helper_helper.rb +93 -0
- data/lib/card/name/all.rb +125 -0
- data/lib/card/name/all/class_methods.rb +28 -0
- data/lib/card/name/all/descendants.rb +46 -0
- data/lib/card/name/all/parts.rb +67 -0
- data/lib/card/query.rb +7 -2
- data/lib/card/query/card_query/interpretation.rb +2 -2
- data/lib/card/query/card_query/sorting.rb +12 -4
- data/lib/card/query/sql_statement.rb +1 -1
- data/lib/card/set/advanced_api.rb +8 -5
- data/lib/card/set/event/options.rb +13 -5
- data/lib/card/set/format.rb +16 -9
- data/lib/card/set/trait.rb +11 -8
- data/lib/card/subcards/add.rb +3 -24
- data/lib/card/subcards/args.rb +42 -0
- data/lib/card/tasks/card/file_card_creator/output_helper.rb +15 -10
- data/lib/card/view/options.rb +2 -1
- data/lib/card/view/permission.rb +14 -3
- data/lib/cardio.rb +9 -66
- data/lib/cardio/defaults.yml +70 -0
- data/lib/cardio/migration.rb +1 -1
- data/mod/core/set/all/assign_attributes.rb +8 -21
- data/mod/core/set/all/initialize.rb +9 -9
- data/mod/core/set/all/name_events.rb +3 -1
- data/mod/core/set/all/references.rb +2 -2
- data/mod/{settings → core}/set/right/autoname.rb +0 -0
- data/mod/{settings → core}/set/self/autoname.rb +0 -0
- data/mod/core/set/type/cardtype.rb +28 -0
- data/mod/{standard → core}/spec/set/type/cardtype_spec.rb +3 -24
- data/mod/standard/file/logo/image-original.svg +1 -59
- metadata +16 -27
- data/config/initializers/uuid_state_file.rb +0 -3
- data/mod/Modfile +0 -4
- data/mod/core/set/all/name.rb +0 -229
- data/mod/core/spec/set/all/name_spec.rb +0 -11
- data/mod/standard/set/all/rich_html/html_views/info.rb +0 -84
- data/mod/standard/set/type/cardtype.rb +0 -119
@@ -0,0 +1,94 @@
|
|
1
|
+
class Card
|
2
|
+
module Model
|
3
|
+
module SaveHelper
|
4
|
+
# private helper methods for public SaveHelper api
|
5
|
+
module SaveArguments
|
6
|
+
private
|
7
|
+
|
8
|
+
# @return args
|
9
|
+
def standardize_args name_or_args, content_or_args=nil, _ignore=nil
|
10
|
+
if name_or_args.is_a?(Hash)
|
11
|
+
name_or_args
|
12
|
+
else
|
13
|
+
add_name name_or_args, content_or_args || {}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def standardize_ensure_args name_or_args, content_or_args
|
18
|
+
name = name_or_args.is_a?(Hash) ? name_or_args[:name] : name_or_args
|
19
|
+
args = if name_or_args.is_a?(Hash)
|
20
|
+
name_or_args
|
21
|
+
else
|
22
|
+
hashify content_or_args, :content
|
23
|
+
end
|
24
|
+
[name, args]
|
25
|
+
end
|
26
|
+
|
27
|
+
def standardize_update_args name_or_args, content_or_args
|
28
|
+
return name_or_args if name_or_args.is_a?(Hash)
|
29
|
+
|
30
|
+
hashify content_or_args, :content
|
31
|
+
end
|
32
|
+
|
33
|
+
def hashify value_or_hash, key
|
34
|
+
if value_or_hash.is_a?(Hash)
|
35
|
+
value_or_hash
|
36
|
+
elsif value_or_hash.nil?
|
37
|
+
{}
|
38
|
+
else
|
39
|
+
{ key => value_or_hash }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def create_args name_or_args, content_or_args=nil
|
44
|
+
args = standardize_args name_or_args, content_or_args
|
45
|
+
resolve_name_conflict args
|
46
|
+
args
|
47
|
+
end
|
48
|
+
|
49
|
+
def name_from_args name_or_args
|
50
|
+
name_or_args.is_a?(Hash) ? name_or_args[:name] : name_or_args
|
51
|
+
end
|
52
|
+
|
53
|
+
def resolve_name_conflict args
|
54
|
+
rename = args.delete :rename_if_conflict
|
55
|
+
return unless args[:name] && rename
|
56
|
+
|
57
|
+
args[:name] = Card.uniquify_name args[:name], rename
|
58
|
+
end
|
59
|
+
|
60
|
+
def ensure_attributes card, args
|
61
|
+
subcards = card.extract_subcard_args! args.symbolize_keys!
|
62
|
+
update_args = changing_args card, args
|
63
|
+
|
64
|
+
return if update_args.empty? && subcards.empty?
|
65
|
+
|
66
|
+
# FIXME: use ensure_attributes for subcards
|
67
|
+
card.update! update_args.merge(subcards: subcards, skip: :validate_renaming)
|
68
|
+
end
|
69
|
+
|
70
|
+
def changing_args card, args
|
71
|
+
args.select do |key, value|
|
72
|
+
case key.to_s
|
73
|
+
when /^\+/
|
74
|
+
changing_field_arg key, value
|
75
|
+
when "name"
|
76
|
+
card.name.to_s != value
|
77
|
+
else
|
78
|
+
standard_changing_arg card, key, value
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def changing_field_arg key, value
|
84
|
+
subfields[key] = value
|
85
|
+
false
|
86
|
+
end
|
87
|
+
|
88
|
+
def standard_changing_arg card, key, value
|
89
|
+
card.send(key) != value unless value.is_a? ::File
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
class Card
|
2
|
+
module Model
|
3
|
+
module SaveHelper
|
4
|
+
# private helper methods for public SaveHelper api
|
5
|
+
module SaveHelperHelper
|
6
|
+
CARDTYPE_METHOD_REGEXP = /^(?<method_name>create|ensure)_(?<type>.+?)(?:_card)?$/
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def codename_from_name name
|
11
|
+
name.downcase.tr(" ", "_").tr(":*", "")
|
12
|
+
end
|
13
|
+
|
14
|
+
def delete_code_card? name
|
15
|
+
return false if name.is_a?(Symbol) && !Codename.exist?(name)
|
16
|
+
|
17
|
+
Card.exist? name
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_coderule_item name, prefix, type_id, to
|
21
|
+
codename = "#{prefix}_#{name.tr(' ', '_').underscore}"
|
22
|
+
name = "#{prefix}: #{name}"
|
23
|
+
|
24
|
+
ensure_card name, type_id: type_id, codename: codename
|
25
|
+
Card[to].add_item! name
|
26
|
+
end
|
27
|
+
|
28
|
+
def method_missing method, *args
|
29
|
+
method_name, cardtype_card = extract_cardtype_from_method_name method
|
30
|
+
return super unless method_name
|
31
|
+
|
32
|
+
sargs = standardize_args(*args)
|
33
|
+
send "#{method_name}_card", sargs.merge(type_id: cardtype_card.id)
|
34
|
+
end
|
35
|
+
|
36
|
+
def respond_to_missing? method, _include_private=false
|
37
|
+
extract_cardtype_from_method_name(method) || super
|
38
|
+
end
|
39
|
+
|
40
|
+
def extract_cardtype_from_method_name method
|
41
|
+
return unless (match = method.match CARDTYPE_METHOD_REGEXP)
|
42
|
+
|
43
|
+
cardtype_card = cardtype_card_from_string match[:type]
|
44
|
+
|
45
|
+
return unless cardtype_card&.type_id == CardtypeID || cardtype_card&.id == SetID
|
46
|
+
|
47
|
+
[match[:method_name], cardtype_card]
|
48
|
+
end
|
49
|
+
|
50
|
+
def cardtype_card_from_string type
|
51
|
+
Card::Codename[type.to_sym] ? Card[type.to_sym] : Card[type]
|
52
|
+
end
|
53
|
+
|
54
|
+
def ensure_card_simplified name, args
|
55
|
+
ensure_card_update(name, args) || Card.create!(add_name(name, args))
|
56
|
+
end
|
57
|
+
|
58
|
+
def ensure_card_update name, args
|
59
|
+
card = Card[name]
|
60
|
+
return unless card
|
61
|
+
|
62
|
+
ensure_attributes card, args
|
63
|
+
card
|
64
|
+
rescue Card::Error::CodenameNotFound => _e
|
65
|
+
false
|
66
|
+
end
|
67
|
+
|
68
|
+
def validate_setting setting
|
69
|
+
return if Codename.exist?(setting) && Card.fetch_type_id(setting) == SettingID
|
70
|
+
|
71
|
+
raise ArgumentError, "not a valid setting: #{setting}"
|
72
|
+
end
|
73
|
+
|
74
|
+
def normalize_trait_rule_args setting, value
|
75
|
+
return value if value.is_a? Hash
|
76
|
+
|
77
|
+
if Card.fetch_type_id([setting, :right, :default]) == PointerID
|
78
|
+
value = Array(value).to_pointer_content
|
79
|
+
end
|
80
|
+
{ content: value }
|
81
|
+
end
|
82
|
+
|
83
|
+
def add_name name, content_or_args
|
84
|
+
if content_or_args.is_a?(Hash)
|
85
|
+
content_or_args.reverse_merge name: name
|
86
|
+
else
|
87
|
+
{ content: content_or_args, name: name }
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
class Card
|
2
|
+
class Name
|
3
|
+
# methods connecting Card to Card::Name
|
4
|
+
module All
|
5
|
+
include Parts
|
6
|
+
include Descendants
|
7
|
+
|
8
|
+
# TODO: use delegations and include more name functions
|
9
|
+
delegate :simple?, :compound?, :junction?, to: :name
|
10
|
+
|
11
|
+
def name
|
12
|
+
@name ||= left_id ? Lexicon.lex_to_name([left_id, right_id]) : super.to_name
|
13
|
+
end
|
14
|
+
|
15
|
+
def key
|
16
|
+
@key ||= left_id ? name.key : super
|
17
|
+
end
|
18
|
+
|
19
|
+
def name= newname
|
20
|
+
@name = superize_name newname.to_name
|
21
|
+
self.key = @name.key
|
22
|
+
update_subcard_names @name
|
23
|
+
write_attribute :name, (@name.simple? ? @name.s : nil)
|
24
|
+
assign_side_ids
|
25
|
+
@name
|
26
|
+
end
|
27
|
+
|
28
|
+
def [] *args
|
29
|
+
case args[0]
|
30
|
+
when Integer, Range
|
31
|
+
fetch_name = Array.wrap(name.parts[args[0]]).compact.join Name.joint
|
32
|
+
Card.fetch(fetch_name, args[1] || {}) unless simple?
|
33
|
+
else
|
34
|
+
super
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def autoname name
|
39
|
+
if Card.exists?(name) || Director.include?(name)
|
40
|
+
autoname name.next
|
41
|
+
else
|
42
|
+
name
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def update_superleft cardname
|
47
|
+
@superleft = @supercard if cardname.field_of? @supercard.name
|
48
|
+
end
|
49
|
+
|
50
|
+
def update_subcard_names new_name, name_to_replace=nil
|
51
|
+
return unless @subcards
|
52
|
+
subcards.each do |subcard|
|
53
|
+
update_subcard_name subcard, new_name, name_to_replace if subcard.new?
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def key= newkey
|
58
|
+
return if newkey == key
|
59
|
+
update_cache_key key do
|
60
|
+
write_attribute :key, (name.simple? ? newkey : nil)
|
61
|
+
@key = newkey
|
62
|
+
end
|
63
|
+
clean_patterns
|
64
|
+
@key
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def assign_side_ids
|
70
|
+
if name.simple?
|
71
|
+
self.left_id = self.right_id = nil
|
72
|
+
else
|
73
|
+
assign_side_id :left_id=, :left_name
|
74
|
+
assign_side_id :right_id=, :right_name
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# assigns left_id and right_id based on names.
|
79
|
+
# if side card is new, id is temporarily stored as -1
|
80
|
+
def assign_side_id side_id_equals, side_name
|
81
|
+
side_id = Lexicon.id(name.send(side_name)) || -1
|
82
|
+
send side_id_equals, side_id
|
83
|
+
end
|
84
|
+
|
85
|
+
def superize_name cardname
|
86
|
+
return cardname unless @supercard
|
87
|
+
|
88
|
+
@supercard.subcards.rename key, cardname.key
|
89
|
+
update_superleft cardname
|
90
|
+
@supercard.name.relative? ? cardname : cardname.absolute_name(@supercard.name)
|
91
|
+
end
|
92
|
+
|
93
|
+
def clean_patterns
|
94
|
+
return unless patterns?
|
95
|
+
reset_patterns
|
96
|
+
patterns
|
97
|
+
end
|
98
|
+
|
99
|
+
def update_cache_key oldkey
|
100
|
+
yield
|
101
|
+
was_in_cache = Card.cache.soft.delete oldkey
|
102
|
+
Card.write_to_soft_cache self if was_in_cache
|
103
|
+
end
|
104
|
+
|
105
|
+
def update_subcard_name subcard, new_name, name_to_replace
|
106
|
+
name_to_replace ||= name_to_replace_for_subcard subcard, new_name
|
107
|
+
subcard.name = subcard.name.swap name_to_replace, new_name.s
|
108
|
+
# following needed? shouldn't #name= trigger this?
|
109
|
+
subcard.update_subcard_names new_name, name
|
110
|
+
end
|
111
|
+
|
112
|
+
def name_to_replace_for_subcard subcard, new_name
|
113
|
+
# if subcard has a relative name like +C
|
114
|
+
# and self is a subcard as well that changed from +B to A+B then
|
115
|
+
# +C should change to A+B+C. #replace doesn't work in this case
|
116
|
+
# because the old name +B is not a part of +C
|
117
|
+
if subcard.name.starts_with_joint? && new_name.parts.first.present?
|
118
|
+
"".to_name
|
119
|
+
else
|
120
|
+
name
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class Card
|
2
|
+
class Name
|
3
|
+
module All
|
4
|
+
# Name-related Card class methods
|
5
|
+
module ClassMethods
|
6
|
+
def rename! oldname, newname
|
7
|
+
Card[oldname].update! name: newname, update_referers: true
|
8
|
+
end
|
9
|
+
|
10
|
+
def uniquify_name name, rename=:new
|
11
|
+
return name unless Card.exists? name
|
12
|
+
uniq_name = generate_alternative_name name
|
13
|
+
return uniq_name unless rename == :old
|
14
|
+
rename!(name, uniq_name)
|
15
|
+
name
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def generate_alternative_name name
|
21
|
+
uniq_name = "#{name} 1"
|
22
|
+
uniq_name.next! while Card.exists?(uniq_name)
|
23
|
+
uniq_name
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
class Card
|
2
|
+
class Name
|
3
|
+
module All
|
4
|
+
# Card methods for finding name children, eg A+B is a child of A and B
|
5
|
+
module Descendants
|
6
|
+
# NOTE: for all these helpers, method returns *all* fields/children/descendants.
|
7
|
+
# (Not just those current user has permission to read.)
|
8
|
+
|
9
|
+
def fields
|
10
|
+
field_ids.map { |id| Card[id] }
|
11
|
+
end
|
12
|
+
|
13
|
+
def field_names
|
14
|
+
field_ids.map { |id| Card::Name[id] }
|
15
|
+
end
|
16
|
+
|
17
|
+
def field_ids
|
18
|
+
child_ids :left
|
19
|
+
end
|
20
|
+
|
21
|
+
def each_child
|
22
|
+
child_ids.each do |id|
|
23
|
+
(child = Card[id]) && yield(child)
|
24
|
+
# check should not be needed (remove after fixing data problems)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# eg, A+B is a child of A and B
|
29
|
+
def child_ids side=nil
|
30
|
+
return [] unless id
|
31
|
+
side ||= name.simple? ? :part : :left_id
|
32
|
+
Auth.as_bot do
|
33
|
+
Card.search({ side => id, return: :id, limit: 0 }, "children of #{name}")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def each_descendant &block
|
38
|
+
each_child do |child|
|
39
|
+
yield child
|
40
|
+
child.each_descendant(&block)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
class Card
|
2
|
+
class Name
|
3
|
+
module All
|
4
|
+
# Card methods for handling name parts, eg A and B are both parts of A+B
|
5
|
+
module Parts
|
6
|
+
def left *args
|
7
|
+
case
|
8
|
+
when simple? then nil
|
9
|
+
when superleft then superleft
|
10
|
+
when name_is_changing? && name.to_name.trunk_name == name_before_act.to_name
|
11
|
+
nil # prevent recursion when, eg, renaming A+B to A+B+C
|
12
|
+
else
|
13
|
+
Card.fetch name.left, *args
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def left_or_new args={}
|
18
|
+
left(args) || Card.new(args.merge(name: name.left))
|
19
|
+
end
|
20
|
+
|
21
|
+
def right *args
|
22
|
+
Card.fetch(name.right, *args) unless simple?
|
23
|
+
end
|
24
|
+
|
25
|
+
def trunk *args
|
26
|
+
simple? ? self : left(*args)
|
27
|
+
end
|
28
|
+
|
29
|
+
def tag *args
|
30
|
+
simple? ? self : Card.fetch(name.right, *args)
|
31
|
+
end
|
32
|
+
|
33
|
+
def right_id= cardish
|
34
|
+
write_card_or_id :right_id, cardish
|
35
|
+
end
|
36
|
+
|
37
|
+
def left_id= cardish
|
38
|
+
write_card_or_id :left_id, cardish
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def write_card_or_id attribute, cardish
|
44
|
+
when_id_exists(cardish) { |id| write_attribute attribute, id }
|
45
|
+
end
|
46
|
+
|
47
|
+
def when_id_exists cardish, &block
|
48
|
+
if (card_id = Card.id cardish)
|
49
|
+
yield card_id
|
50
|
+
elsif cardish.is_a? Card
|
51
|
+
with_id_after_store cardish, &block
|
52
|
+
else
|
53
|
+
yield cardish # eg nil
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# subcards are usually saved after super cards;
|
58
|
+
# after_store forces it to save the subcard first
|
59
|
+
# and callback afterwards
|
60
|
+
def with_id_after_store subcard
|
61
|
+
add_subcard subcard
|
62
|
+
subcard.director.after_store { |card| yield card.id }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|