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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/config/locales/en.yml +9 -6
  4. data/db/migrate_core_cards/data/decko_logo.svg +1 -59
  5. data/lib/card.rb +3 -0
  6. data/lib/card/content/diff/result.rb +40 -29
  7. data/lib/card/env.rb +2 -2
  8. data/lib/card/model/save_helper.rb +16 -182
  9. data/lib/card/model/save_helper/save_arguments.rb +94 -0
  10. data/lib/card/model/save_helper/save_helper_helper.rb +93 -0
  11. data/lib/card/name/all.rb +125 -0
  12. data/lib/card/name/all/class_methods.rb +28 -0
  13. data/lib/card/name/all/descendants.rb +46 -0
  14. data/lib/card/name/all/parts.rb +67 -0
  15. data/lib/card/query.rb +7 -2
  16. data/lib/card/query/card_query/interpretation.rb +2 -2
  17. data/lib/card/query/card_query/sorting.rb +12 -4
  18. data/lib/card/query/sql_statement.rb +1 -1
  19. data/lib/card/set/advanced_api.rb +8 -5
  20. data/lib/card/set/event/options.rb +13 -5
  21. data/lib/card/set/format.rb +16 -9
  22. data/lib/card/set/trait.rb +11 -8
  23. data/lib/card/subcards/add.rb +3 -24
  24. data/lib/card/subcards/args.rb +42 -0
  25. data/lib/card/tasks/card/file_card_creator/output_helper.rb +15 -10
  26. data/lib/card/view/options.rb +2 -1
  27. data/lib/card/view/permission.rb +14 -3
  28. data/lib/cardio.rb +9 -66
  29. data/lib/cardio/defaults.yml +70 -0
  30. data/lib/cardio/migration.rb +1 -1
  31. data/mod/core/set/all/assign_attributes.rb +8 -21
  32. data/mod/core/set/all/initialize.rb +9 -9
  33. data/mod/core/set/all/name_events.rb +3 -1
  34. data/mod/core/set/all/references.rb +2 -2
  35. data/mod/{settings → core}/set/right/autoname.rb +0 -0
  36. data/mod/{settings → core}/set/self/autoname.rb +0 -0
  37. data/mod/core/set/type/cardtype.rb +28 -0
  38. data/mod/{standard → core}/spec/set/type/cardtype_spec.rb +3 -24
  39. data/mod/standard/file/logo/image-original.svg +1 -59
  40. metadata +16 -27
  41. data/config/initializers/uuid_state_file.rb +0 -3
  42. data/mod/Modfile +0 -4
  43. data/mod/core/set/all/name.rb +0 -229
  44. data/mod/core/spec/set/all/name_spec.rb +0 -11
  45. data/mod/standard/set/all/rich_html/html_views/info.rb +0 -84
  46. 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