card 1.18.0 → 1.18.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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/card.gemspec +20 -16
  4. data/db/migrate_core_cards/20150202143810_import_bootstrap_layout.rb +1 -1
  5. data/db/schema.rb +110 -92
  6. data/lib/card.rb +1 -0
  7. data/lib/card/content.rb +4 -73
  8. data/lib/card/content/chunk.rb +119 -0
  9. data/lib/card/content/parser.rb +75 -0
  10. data/lib/card/diff.rb +25 -398
  11. data/lib/card/diff/lcs.rb +247 -0
  12. data/lib/card/diff/result.rb +131 -0
  13. data/lib/card/director_register.rb +5 -0
  14. data/lib/card/query/attributes.rb +19 -13
  15. data/lib/card/set/event.rb +2 -1
  16. data/lib/card/set_pattern.rb +4 -2
  17. data/lib/card/spec_helper.rb +7 -1
  18. data/lib/card/stage_director.rb +33 -5
  19. data/lib/card/subcards.rb +11 -3
  20. data/lib/card/subdirector_array.rb +14 -1
  21. data/lib/cardio.rb +8 -5
  22. data/mod/01_core/chunk/include.rb +2 -2
  23. data/mod/01_core/chunk/link.rb +3 -3
  24. data/mod/01_core/chunk/literal.rb +20 -14
  25. data/mod/01_core/chunk/query_reference.rb +2 -2
  26. data/mod/01_core/chunk/reference.rb +47 -38
  27. data/mod/01_core/chunk/uri.rb +17 -13
  28. data/mod/01_core/format/html_format.rb +0 -2
  29. data/mod/01_core/set/all/actify.rb +12 -1
  30. data/mod/01_core/set/all/collection.rb +4 -4
  31. data/mod/01_core/set/all/fetch.rb +0 -27
  32. data/mod/01_core/set/all/name.rb +33 -12
  33. data/mod/01_core/set/all/pattern.rb +2 -6
  34. data/mod/01_core/set/all/phases.rb +0 -1
  35. data/mod/01_core/set/all/references.rb +2 -2
  36. data/mod/01_core/set/all/rules.rb +10 -3
  37. data/mod/01_core/set/all/tracked_attributes.rb +0 -1
  38. data/mod/01_core/set/all/type.rb +0 -14
  39. data/mod/01_core/spec/chunk/literal_spec.rb +1 -1
  40. data/mod/01_core/spec/chunk/uri_spec.rb +204 -201
  41. data/mod/01_core/spec/set/all/type_spec.rb +3 -1
  42. data/mod/01_history/lib/card/action.rb +7 -9
  43. data/mod/01_history/set/all/history.rb +6 -1
  44. data/mod/02_basic_types/set/all/all_csv.rb +1 -1
  45. data/mod/02_basic_types/set/type/pointer.rb +20 -9
  46. data/mod/03_machines/lib/javascript/wagn.js.coffee +1 -1
  47. data/mod/04_settings/set/right/structure.rb +7 -1
  48. data/mod/05_email/set/right/follow.rb +22 -22
  49. data/mod/05_email/set/type_plus_right/user/follow.rb +25 -26
  50. data/mod/05_standard/set/all/rich_html/wrapper.rb +12 -6
  51. data/mod/05_standard/set/rstar/rules_editor.rb +6 -4
  52. data/mod/05_standard/set/self/all.rb +0 -10
  53. data/mod/05_standard/set/self/stats.rb +6 -15
  54. data/mod/05_standard/set/type/set.rb +0 -6
  55. data/mod/05_standard/spec/chunk/include_spec.rb +2 -2
  56. data/mod/05_standard/spec/chunk/link_spec.rb +1 -1
  57. data/mod/05_standard/spec/chunk/query_reference_spec.rb +5 -4
  58. data/spec/lib/card/chunk_spec.rb +7 -5
  59. data/spec/lib/card/content_spec.rb +11 -11
  60. data/spec/lib/card/diff_spec.rb +4 -4
  61. data/spec/lib/card/stage_director_spec.rb +56 -0
  62. data/spec/lib/card/subcards_spec.rb +0 -1
  63. data/spec/models/card/type_transition_spec.rb +5 -42
  64. metadata +12 -23
  65. data/lib/card/chunk.rb +0 -122
@@ -68,7 +68,8 @@ class Card
68
68
  def define_event_method event, call_method, _opts
69
69
  class_eval do
70
70
  define_method event do
71
- # puts "#{name}:#{event}".green
71
+ # puts "#{name}:#{event}".red
72
+ # puts "#{Card::DirectorRegister.to_s}".green
72
73
  run_callbacks event do
73
74
  send call_method
74
75
  end
@@ -94,7 +94,8 @@ EOF
94
94
  if self.class.anchorless?
95
95
  self.class.pattern_code.camelize
96
96
  elsif anchor_codenames
97
- "#{self.class.pattern_code.camelize}::#{anchor_codenames.map(&:to_s).map(&:camelize) * '::'}"
97
+ codenames = [self.class.pattern_code] + anchor_codenames.map(&:to_s)
98
+ codenames.map(&:camelize).join '::'
98
99
  end
99
100
  end
100
101
  end
@@ -108,7 +109,8 @@ EOF
108
109
  end
109
110
 
110
111
  def format_module_list klass
111
- (hash = Card::Set.modules[:nonbase_format][klass]) && lookup_module_list(hash)
112
+ hash = Card::Set.modules[:nonbase_format][klass]
113
+ hash && lookup_module_list(hash)
112
114
  end
113
115
 
114
116
  def anchor_codenames
@@ -89,7 +89,13 @@ module Card::SpecHelper
89
89
  stage_sym = :"#{stage}_stage"
90
90
  $rspec_binding = binding
91
91
  add_test_event stage_sym, :in_stage_test, &event_block
92
- opts[:trigger].call
92
+ trigger =
93
+ if opts[:trigger].is_a?(Symbol)
94
+ method(opts[:trigger])
95
+ else
96
+ opts[:trigger]
97
+ end
98
+ trigger.call
93
99
  ensure
94
100
  remove_test_event stage_sym, :in_stage_test
95
101
  end
@@ -42,7 +42,10 @@ class Card
42
42
  def initialize card, opts={}, main=true
43
43
  @card = card
44
44
  @card.director = self
45
- @card.prepare_for_phases
45
+ # for read actions there is no validation phase
46
+ # so we have to set the action here
47
+ @card.identify_action
48
+
46
49
  @stage = nil
47
50
  @running = false
48
51
  @parent = opts[:parent]
@@ -58,15 +61,22 @@ class Card
58
61
  end
59
62
 
60
63
  def unregister
64
+ Card::DirectorRegister.delete self
65
+ end
66
+
67
+ def delete
61
68
  @card.director = nil
62
- @subdirectors = nil
69
+ @subdirectors.clear
63
70
  @stage = nil
64
71
  @action = nil
65
- Card::DirectorRegister.delete self
72
+ end
73
+
74
+ def prepare_for_phases
75
+ @card.prepare_for_phases
76
+ @subdirectors.each(&:prepare_for_phases)
66
77
  end
67
78
 
68
79
  def validation_phase
69
- @running = true
70
80
  run_single_stage :initialize
71
81
  run_single_stage :prepare_to_validate
72
82
  run_single_stage :validate
@@ -124,13 +134,26 @@ class Card
124
134
  end
125
135
  end
126
136
 
137
+ def to_s
138
+ str = @card.name.to_s.clone
139
+ if @subdirectors
140
+ subs = subdirectors.map(&:card)
141
+ .map { |card| " #{card.name}" }.join "\n"
142
+ str << "\n#{subs}"
143
+ end
144
+ str
145
+ end
146
+
127
147
  private
128
148
 
129
149
  def run_single_stage stage, &block
130
150
  # puts "#{@card.name}: #{stage} stage".red
131
151
  @stage = stage_index stage
132
152
  return if @card.errors.any? && @stage <= stage_index(:validate)
133
-
153
+ if stage == :initialize
154
+ @running ||= true
155
+ prepare_for_phases
156
+ end
134
157
  # in the store stage it can be necessary that
135
158
  # other subcards must be saved before we save this card
136
159
  if stage == :store
@@ -227,5 +250,10 @@ class Card
227
250
  def initialize card, opts={}
228
251
  super card, opts, false
229
252
  end
253
+
254
+ def delete
255
+ @parent.subdirectors.delete self if @parent
256
+ super
257
+ end
230
258
  end
231
259
  end
data/lib/card/subcards.rb CHANGED
@@ -27,6 +27,9 @@ class Card
27
27
 
28
28
  def clear
29
29
  @keys.each do |key|
30
+ if (subcard = fetch_subcard key)
31
+ Card::DirectorRegister.delete subcard.director
32
+ end
30
33
  Card.cache.soft.delete key
31
34
  end
32
35
  @keys = ::Set.new
@@ -54,6 +57,10 @@ class Card
54
57
  key = absolutize_subcard_name(key).key unless @keys.include?(key)
55
58
  @keys.delete key
56
59
  removed_card = fetch_subcard key
60
+ if removed_card.current_action
61
+ removed_card.current_action.delete
62
+ end
63
+ Card::DirectorRegister.delete removed_card.director
57
64
  Card.cache.soft.delete key
58
65
  removed_card
59
66
  end
@@ -95,9 +102,10 @@ class Card
95
102
  end
96
103
  end
97
104
 
98
- def rename old_name, _new_name
105
+ def rename old_name, new_name
99
106
  return unless @keys.include? old_name.to_name.key
100
- # FIXME: something should happen here
107
+ @keys.delete old_name.to_name.key
108
+ @keys << new_name.to_name.key
101
109
  end
102
110
 
103
111
  def << value
@@ -223,7 +231,7 @@ class Card
223
231
  end
224
232
 
225
233
  def absolutize_subcard_name name
226
- if @context_card.name =~ /^\+/
234
+ if @context_card.name =~ /^\+/ || name.blank?
227
235
  name.to_name
228
236
  else
229
237
  name.to_name.to_absolute_name(@context_card.name)
@@ -14,6 +14,9 @@ class Card
14
14
  end
15
15
 
16
16
  def add card
17
+ if card.is_a? Card::StageDirector
18
+ card = card.card
19
+ end
17
20
  each do |dir|
18
21
  return dir if dir.card == card
19
22
  end
@@ -24,8 +27,18 @@ class Card
24
27
  dir
25
28
  end
26
29
 
30
+ alias_method :delete_director, :delete
31
+
27
32
  def delete card
28
- delete_if { |dir| dir.card == card }
33
+ if card.is_a? Card::StageDirector
34
+ delete_director card
35
+ else
36
+ delete_if { |dir| dir.card == card }
37
+ end
38
+ end
39
+
40
+ def add_director dir
41
+ add dir.card
29
42
  end
30
43
  end
31
44
  end
data/lib/cardio.rb CHANGED
@@ -92,14 +92,17 @@ module Cardio
92
92
  add_path 'db/migrate_deck_cards', root: root, with: 'db/migrate_cards'
93
93
  add_path 'db/seeds', with: 'db/seeds.rb'
94
94
 
95
- add_path 'config/initializers', glob: '**/*.rb'
95
+ add_path 'config/initializers', glob: '**/*.rb'
96
+ add_initializers root
96
97
  end
97
98
 
98
99
  def set_mod_paths
99
- each_mod_path do |mod_path|
100
- Dir.glob("#{mod_path}/*/initializers").each do |initializers_dir|
101
- paths['config/initializers'] << initializers_dir
102
- end
100
+ each_mod_path { |mod_path| add_initializers mod_path }
101
+ end
102
+
103
+ def add_initializers dir
104
+ Dir.glob("#{dir}/config/initializers").each do |initializers_dir|
105
+ paths['config/initializers'] << initializers_dir
103
106
  end
104
107
  end
105
108
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  require_dependency File.expand_path('../reference', __FILE__)
4
4
 
5
- module Card::Chunk
5
+ module Card::Content::Chunk
6
6
  class Include < Reference
7
7
  cattr_reader :options
8
8
  @@options = ::Set.new [
@@ -23,7 +23,7 @@ module Card::Chunk
23
23
  ]
24
24
  attr_reader :options
25
25
 
26
- Card::Chunk.register_class(
26
+ Card::Content::Chunk.register_class(
27
27
  self, prefix_re: '\\{\\{',
28
28
  full_re: /^\{\{([^\}]*)\}\}/,
29
29
  idx_char: '{')
@@ -2,11 +2,11 @@
2
2
 
3
3
  require_dependency File.expand_path('../reference', __FILE__)
4
4
 
5
- module Card::Chunk
5
+ module Card::Content::Chunk
6
6
  class Link < Reference
7
7
  attr_reader :link_text
8
8
  # Groups: $1, [$2]: [[$1]] or [[$1|$2]] or $3, $4: [$3][$4]
9
- Card::Chunk.register_class self,
9
+ Card::Content::Chunk.register_class self,
10
10
  prefix_re: '\\[',
11
11
  full_re: /^\[\[([^\]]+)\]\]/,
12
12
  idx_char: '['
@@ -78,7 +78,7 @@ module Card::Chunk
78
78
  replace_name_reference old_name, new_name
79
79
 
80
80
  if Card::Content === @link_text
81
- @link_text.find_chunks(Card::Chunk::Reference).each do |chunk|
81
+ @link_text.find_chunks(Card::Content::Chunk::Reference).each do |chunk|
82
82
  chunk.replace_reference old_name, new_name
83
83
  end
84
84
  elsif old_name.to_name == @link_text
@@ -1,21 +1,27 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
 
3
- # These are basic chunks that have a pattern and can be protected.
4
- # They are used by rendering process to prevent wiki rendering
5
- # occuring within literal areas such as <code> and <pre> blocks
6
- # and within HTML tags.
7
- module Card::Chunk
8
- class EscapedLiteral < Abstract
9
- FULL_RE = { '[' => /^\\\[\[[^\]]*\]\]/, '{' => /^\\\{\{[^\}]*\}\}/ }.freeze
10
- Card::Chunk.register_class self, prefix_re: '\\\\(?:\\[\\[|\\{\\{)',
11
- idx_char: '\\'
3
+ class Card
4
+ class Content
5
+ module Chunk
6
+ # These are basic chunks that have a pattern and can be protected.
7
+ # They are used by rendering process to prevent wiki rendering
8
+ # occuring within literal areas such as <code> and <pre> blocks
9
+ # and within HTML tags.
10
+ class EscapedLiteral < Abstract
11
+ FULL_RE = { '[' => /^\\\[\[[^\]]*\]\]/,
12
+ '{' => /^\\\{\{[^\}]*\}\}/ }.freeze
13
+ Card::Content::Chunk.register_class self,
14
+ prefix_re: '\\\\(?:\\[\\[|\\{\\{)',
15
+ idx_char: '\\'
12
16
 
13
- def self.full_re prefix
14
- re = FULL_RE[prefix[1, 1]]
15
- end
17
+ def self.full_re prefix
18
+ FULL_RE[prefix[1, 1]]
19
+ end
16
20
 
17
- def interpret match, _content
18
- @process_chunk = match[0].sub(/^\\(.)/, '<span>\\1</span>')
21
+ def interpret match, _content
22
+ @process_chunk = match[0].sub(/^\\(.)/, '<span>\\1</span>')
23
+ end
24
+ end
19
25
  end
20
26
  end
21
27
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  require_dependency File.expand_path('../reference', __FILE__)
4
4
 
5
- module Card::Chunk
5
+ module Card::Content::Chunk
6
6
  # This should find +Alfred+ in expressions like
7
7
  # 1) {"name":"Alfred"}
8
8
  # 2a) {"name":["in","Alfred"]}
@@ -26,7 +26,7 @@ module Card::Chunk
26
26
  ).map(&:to_name)
27
27
  )
28
28
 
29
- Card::Chunk.register_class(
29
+ Card::Content::Chunk.register_class(
30
30
  self, prefix_re: '(?<=[:,\\[])\\s*"',
31
31
  # we check for colon, comma or square bracket before a quote
32
32
  # we have to use a lookbehind, otherwise
@@ -1,51 +1,60 @@
1
1
  # -*- encoding : utf-8 -*-
2
- module Card::Chunk
3
- class Reference < Abstract
4
- attr_accessor :referee_name, :name
2
+ class Card
3
+ class Content
4
+ module Chunk
5
+ class Reference < Abstract
6
+ attr_accessor :referee_name, :name
5
7
 
6
- def referee_name
7
- return if name.nil?
8
+ def referee_name
9
+ return if name.nil?
10
+ @referee_name ||=
11
+ begin
12
+ rendered_name = render_obj(name)
13
+ ref_card = fetch_referee_card rendered_name
14
+ ref_card ? ref_card.cardname : rendered_name.to_name
15
+ end
16
+ @referee_name = @referee_name.to_absolute(card.cardname).to_name
17
+ end
18
+
19
+ def referee_card
20
+ @referee_card ||= referee_name && Card.fetch(referee_name)
21
+ end
22
+
23
+ # FIXME: if we need this, then it should be faster, using fetch_id
24
+ # def referee_id
25
+ # referee_card and referee_card.id
26
+ # end
27
+
28
+ def replace_name_reference old_name, new_name
29
+ @referee_card = nil
30
+ @referee_name = nil
31
+ if name.is_a? Card::Content
32
+ name.find_chunks(Chunk::Reference).each do |chunk|
33
+ chunk.replace_reference old_name, new_name
34
+ end
35
+ else
36
+ @name = name.to_name.replace_part(old_name, new_name)
37
+ end
38
+ end
39
+
40
+ def render_obj raw
41
+ if format && raw.is_a?(Card::Content)
42
+ format.process_content raw
43
+ else
44
+ raw
45
+ end
46
+ end
8
47
 
9
- @referee_name ||= begin
10
- rendered_name = render_obj(name)
11
- ref_card =
48
+ private
49
+
50
+ def fetch_referee_card rendered_name
12
51
  case rendered_name # FIXME: this should be standard fetch option.
13
52
  when /^\~(\d+)$/ # get by id
14
53
  Card.fetch Regexp.last_match(1).to_i
15
54
  when /^\:(\w+)$/ # get by codename
16
55
  Card.fetch Regexp.last_match(1).to_sym
17
56
  end
18
- ref_card ? ref_card.cardname : rendered_name.to_name
19
- end
20
- @referee_name = @referee_name.to_absolute(card.cardname).to_name
21
- end
22
-
23
- def referee_card
24
- @referee_card ||= referee_name && Card.fetch(referee_name)
25
- end
26
-
27
- # FIXME: if we need this, then it should be faster, using fetch_id
28
- # def referee_id
29
- # referee_card and referee_card.id
30
- # end
31
-
32
- def replace_name_reference old_name, new_name
33
- @referee_card = nil
34
- @referee_name = nil
35
- if Card::Content === name
36
- name.find_chunks(Chunk::Reference).each do |chunk|
37
- chunk.replace_reference old_name, new_name
38
57
  end
39
- else
40
- @name = name.to_name.replace_part(old_name, new_name)
41
- end
42
- end
43
-
44
- def render_obj raw
45
- if format && Card::Content === raw
46
- format.process_content raw
47
- else
48
- raw
49
58
  end
50
59
  end
51
60
  end
@@ -16,7 +16,7 @@ require 'uri'
16
16
  # I'm using a part of the [ISO 3166-1 Standard][iso3166] for country name suffixes.
17
17
  # The generic names are from www.bnoack.com/data/countrycode2.html)
18
18
  # [iso3166]: http://geotags.com/iso3166/
19
- module Card::Chunk
19
+ module Card::Content::Chunk
20
20
  class URI < Abstract
21
21
  SCHEMES = %w(irc http https ftp ssh git sftp file ldap ldaps mailto).freeze
22
22
 
@@ -25,9 +25,11 @@ module Card::Chunk
25
25
  attr_reader :uri, :link_text
26
26
  delegate :to, :scheme, :host, :port, :path, :query, :fragment, to: :uri
27
27
 
28
- Card::Chunk.register_class self, prefix_re: "(?:(?!#{REJECTED_PREFIX_RE})(?:#{SCHEMES * '|'})\\:)",
29
- full_re: /^#{::URI.regexp(SCHEMES)}/,
30
- idx_char: ':'
28
+ Card::Content::Chunk.register_class(
29
+ self, prefix_re: "(?:(?!#{REJECTED_PREFIX_RE})(?:#{SCHEMES * '|'})\\:)",
30
+ full_re: /^#{::URI.regexp(SCHEMES)}/,
31
+ idx_char: ':'
32
+ )
31
33
 
32
34
  class << self
33
35
  def full_match content, prefix
@@ -75,11 +77,12 @@ module Card::Chunk
75
77
  PREPEND_STR = 'mailto:'.freeze
76
78
  EMAIL = '[a-zA-Zd](?:[-a-zA-Zd]*[a-zA-Zd])?\\@'.freeze
77
79
 
78
- Card::Chunk.register_class self, prefix_re: "(?:(?!#{REJECTED_PREFIX_RE})#{EMAIL})\\b",
79
- full_re: /^#{::URI.regexp(SCHEMES)}/,
80
- prepend_str: PREPEND_STR,
81
- idx_char: '@'
82
-
80
+ Card::Content::Chunk.register_class(
81
+ self, prefix_re: "(?:(?!#{REJECTED_PREFIX_RE})#{EMAIL})\\b",
82
+ full_re: /^#{::URI.regexp(SCHEMES)}/,
83
+ prepend_str: PREPEND_STR,
84
+ idx_char: '@'
85
+ )
83
86
  def interpret match, content
84
87
  super
85
88
  @text = @text.sub(/^mailto:/, '') # this removes the prepended string from the unchanged match text
@@ -110,10 +113,11 @@ module Card::Chunk
110
113
  PREPEND_STR = 'http://'.freeze
111
114
  HOST = "(?:[a-zA-Z\d](?:[-a-zA-Z\d]*[a-zA-Z\d])?\\.)+#{TLDS}".freeze
112
115
 
113
- Card::Chunk.register_class self, prefix_re: "(?:(?!#{REJECTED_PREFIX_RE})#{HOST})\\b",
114
- full_re: /^#{::URI.regexp(SCHEMES)}/,
115
- prepend_str: PREPEND_STR
116
-
116
+ Card::Content::Chunk.register_class(
117
+ self, prefix_re: "(?:(?!#{REJECTED_PREFIX_RE})#{HOST})\\b",
118
+ full_re: /^#{::URI.regexp(SCHEMES)}/,
119
+ prepend_str: PREPEND_STR
120
+ )
117
121
  def interpret match, content
118
122
  super
119
123
  @text = @text.sub(/^http:\/\//, '') # this removes the prepended string from the unchanged match text