card 1.101.0 → 1.101.1

Sign up to get free protection for your applications and to get access to all the features.
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