card 1.18.4 → 1.18.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.yardoc/checksums +263 -240
  3. data/.yardoc/object_types +0 -0
  4. data/.yardoc/objects/root.dat +0 -0
  5. data/VERSION +1 -1
  6. data/card.gemspec +5 -2
  7. data/config/initializers/01_core_extensions/array.rb +9 -0
  8. data/config/initializers/01_core_extensions/hash.rb +57 -0
  9. data/config/initializers/01_core_extensions/module.rb +14 -0
  10. data/config/initializers/01_core_extensions/object.rb +43 -0
  11. data/config/initializers/02_extensions/kaminari.rb +38 -0
  12. data/config/initializers/core_extensions.rb +24 -0
  13. data/config/initializers/extensions.rb +3 -0
  14. data/lib/card.rb +15 -10
  15. data/lib/card/director_register.rb +7 -0
  16. data/lib/card/loader.rb +29 -39
  17. data/lib/card/migration.rb +14 -0
  18. data/lib/card/query.rb +17 -128
  19. data/lib/card/query/attributes.rb +2 -244
  20. data/lib/card/query/conjunctions.rb +36 -0
  21. data/lib/card/query/helpers.rb +72 -0
  22. data/lib/card/query/interpretation.rb +124 -0
  23. data/lib/card/query/relational_attributes.rb +95 -0
  24. data/lib/card/query/sorting.rb +52 -0
  25. data/lib/card/set.rb +73 -362
  26. data/lib/card/set/format.rb +122 -0
  27. data/lib/card/set/helpers.rb +100 -0
  28. data/lib/card/set/loader.rb +98 -0
  29. data/lib/card/set/trait.rb +5 -2
  30. data/lib/card/subcards.rb +38 -12
  31. data/lib/cardio.rb +1 -1
  32. data/lib/generators/card/migration/templates/card_migration.erb +1 -1
  33. data/mod/01_core/chunk/include.rb +13 -1
  34. data/mod/01_core/set/all/event.rb +14 -0
  35. data/mod/01_core/set/all/fetch.rb +21 -7
  36. data/mod/01_core/set/all/states.rb +3 -1
  37. data/mod/01_core/set/all/subcards.rb +4 -2
  38. data/mod/01_core/spec/set/all/fetch_spec.rb +14 -1
  39. data/mod/02_basic_types/set/abstract/code_file.rb +6 -0
  40. data/mod/04_settings/set/type/setting.rb +10 -0
  41. data/mod/05_standard/set/all/rich_html/wrapper.rb +1 -1
  42. data/mod/05_standard/set/self/codenames.rb +0 -0
  43. data/mod/05_standard/spec/chunk/include_spec.rb +10 -10
  44. data/spec/config/initializers/core_extensions_spec.rb +15 -0
  45. data/spec/lib/card/stage_director_spec.rb +25 -1
  46. metadata +25 -8
  47. data/config/initializers/01_init_ruby_extensions.rb +0 -3
  48. data/lib/card/core_ext.rb +0 -107
@@ -22,6 +22,7 @@ module Card::Content::Chunk
22
22
  :variant #
23
23
  ]
24
24
  attr_reader :options
25
+ DEFAULT_OPTION = :view # a value without a key is interpreted as view
25
26
 
26
27
  Card::Content::Chunk.register_class(
27
28
  self, prefix_re: '\\{\\{',
@@ -68,7 +69,7 @@ module Card::Content::Chunk
68
69
  end
69
70
 
70
71
  def option_string_to_hash list_string, options_hash, style_hash
71
- Hash.new_from_semicolon_attr_list(list_string).each do |key, value|
72
+ each_option(list_string) do |key, value|
72
73
  key = key.to_sym
73
74
  if key == :item
74
75
  options_hash[:items] ||= {}
@@ -115,5 +116,16 @@ module Card::Content::Chunk
115
116
  @text.sub! '}}', "|#{view}}}"
116
117
  end
117
118
  end
119
+
120
+ private
121
+
122
+ def each_option attr_string
123
+ return if attr_string.blank?
124
+ attr_string.strip.split(';').each do |pair|
125
+ value, key = pair.split(':').reverse
126
+ key ||= self.class::DEFAULT_OPTION.to_s
127
+ yield key.strip, value.strip
128
+ end
129
+ end
118
130
  end
119
131
  end
@@ -15,6 +15,20 @@ end
15
15
 
16
16
  private
17
17
 
18
+ def wrong_stage opts
19
+ return false if director.stage_ok? opts
20
+ if !stage
21
+ "phase method #{method} called outside of event phases"
22
+ else
23
+ "#{opts.inspect} method #{method} called in stage #{stage}"
24
+ end
25
+ end
26
+
27
+ def wrong_action action
28
+ return false if on_condition_applies? action
29
+ "on: #{action} method #{method} called on #{@action}"
30
+ end
31
+
18
32
  def on_condition_applies? action
19
33
  if action
20
34
  Array.wrap(action).member? @action
@@ -15,6 +15,8 @@ module ClassMethods
15
15
  # 1. a numeric id (Integer)
16
16
  # 2. a name/key (String or Card::Name)
17
17
  # 3. a codename (Symbol)
18
+ # or any combination of those. If you pass more then one mark they get
19
+ # joined with a '+'
18
20
  # @param [Hash] opts ({})
19
21
  # Options:
20
22
  # :skip_virtual Real cards only
@@ -23,10 +25,9 @@ module ClassMethods
23
25
  # :local_only Use only local cache for lookup and storing
24
26
  # new: { card opts } Return a new card when not found
25
27
  #
26
- def fetch mark, opts={}
28
+ def fetch *args
29
+ mark, opts = normalize_fetch_args args
27
30
  validate_fetch_opts! opts
28
- mark = normalize_mark mark, opts
29
-
30
31
  card, needs_caching = fetch_existing mark, opts
31
32
 
32
33
  if (new_card = new_for_cache card, mark, opts)
@@ -76,8 +77,8 @@ module ClassMethods
76
77
  fetch mark, opts.merge(local_only: true)
77
78
  end
78
79
 
79
- def fetch_id mark, opts={}
80
- mark = normalize_mark mark, opts
80
+ def fetch_id *args
81
+ mark, _opts = normalize_fetch_args args
81
82
  if mark.is_a?(Integer)
82
83
  mark
83
84
  else
@@ -99,8 +100,8 @@ module ClassMethods
99
100
  end
100
101
  end
101
102
 
102
- def [] mark
103
- fetch mark, skip_virtual: true
103
+ def [] *marks
104
+ fetch(*marks, skip_virtual: true)
104
105
  end
105
106
 
106
107
  def exists? mark
@@ -224,6 +225,19 @@ module ClassMethods
224
225
  Card.cache.soft.write "~#{card.id}", card.key if card.id && card.id != 0
225
226
  end
226
227
 
228
+ def compose_mark parts, opts
229
+ return normalize_mark(parts.first, opts) if parts.size == 1
230
+ parts.map do |p|
231
+ normalized = normalize_mark p, {}
232
+ normalized.is_a?(Integer) ? fetch(normalized).name : normalized.to_s
233
+ end.join('+').to_name
234
+ end
235
+
236
+ def normalize_fetch_args args
237
+ opts = args.last.is_a?(Hash) ? args.pop : {}
238
+ [compose_mark(args, opts), opts]
239
+ end
240
+
227
241
  def normalize_mark mark, opts
228
242
  case mark
229
243
  when Symbol then Card::Codename[mark]
@@ -18,5 +18,7 @@ end
18
18
 
19
19
  def pristine?
20
20
  # has not been edited directly by human users. bleep blorp.
21
- new_card? || !actions.joins(:act).where('card_acts.actor_id != ?', Card::WagnBotID).exists?
21
+ new_card? || !actions.joins(:act).where(
22
+ 'card_acts.actor_id != ?', Card::WagnBotID
23
+ ).exists?
22
24
  end
@@ -21,13 +21,15 @@ def add_subfield name_or_card, args=nil
21
21
  subcards.add_field name_or_card, args
22
22
  end
23
23
 
24
- def remove_subcard name_or_card
24
+ def detach_subcard name_or_card
25
25
  subcards.remove name_or_card
26
26
  end
27
+ alias_method :remove_subcard, :detach_subcard
27
28
 
28
- def remove_subfield name_or_card
29
+ def detach_subfield name_or_card
29
30
  subcards.remove_field name_or_card
30
31
  end
32
+ alias_method :remove_subfield, :detach_subfield
31
33
 
32
34
  def clear_subcards
33
35
  subcards.clear
@@ -1,7 +1,7 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
 
3
3
  describe Card::Set::All::Fetch do
4
- describe '.fetch' do
4
+ describe '#fetch' do
5
5
  it 'returns and caches existing cards' do
6
6
  card_double = class_double('Card')
7
7
  expect(Card.fetch('A')).to be_instance_of(Card)
@@ -72,6 +72,18 @@ describe Card::Set::All::Fetch do
72
72
  .to eq('Yomama')
73
73
  end
74
74
 
75
+ it 'fetches junction of names' do
76
+ card = Card.fetch 'A', 'B'
77
+ expect(card).to be_instance_of(Card)
78
+ expect(card.name).to eq 'A+B'
79
+ end
80
+
81
+ it 'fetches junction of name, id, and codename' do
82
+ card = Card.fetch 'Book', Card.fetch_id(:type), :structure
83
+ expect(card).to be_instance_of(Card)
84
+ expect(card.name).to eq 'Book+*type+*structure'
85
+ end
86
+
75
87
  it 'does not recurse infinitely on template templates' do
76
88
  expect(Card.fetch('*structure+*right+*structure')).to be_nil
77
89
  end
@@ -104,6 +116,7 @@ describe Card::Set::All::Fetch do
104
116
  a.save!
105
117
  end
106
118
  end
119
+
107
120
  describe 'default option' do
108
121
  context "when card doesn't exist" do
109
122
  it 'initializes new cards' do
@@ -38,6 +38,12 @@ def find_file filename
38
38
  nil
39
39
  end
40
40
 
41
+ def existing_source_paths
42
+ Array.wrap(source_files).map do |filename|
43
+ find_file(filename)
44
+ end.compact
45
+ end
46
+
41
47
  view :raw do |_args|
42
48
  Array.wrap(card.source_files).map do |filename|
43
49
  if (source_path = card.find_file(filename))
@@ -12,6 +12,16 @@ def self.member_names
12
12
  end
13
13
  end
14
14
 
15
+ format :data do
16
+ view :core do |_args|
17
+ wql = { left: { type: Card::SetID },
18
+ right: card.id,
19
+ limit: 0
20
+ }
21
+ Card.search(wql).compact.map { |c| nest c }
22
+ end
23
+ end
24
+
15
25
  view :core do |args|
16
26
  klasses = Card.set_patterns.reverse.map do |set_class|
17
27
  wql = { left: { type: Card::SetID },
@@ -99,7 +99,7 @@ format :html do
99
99
 
100
100
  def frame_and_form action, args={}, form_opts={}
101
101
  form_opts.merge! args.delete(:form_opts) if args[:form_opts]
102
- form_opts[:hidden] = args.delete(:hidden)
102
+ form_opts[:hidden] = args.delete(:hidden) if args[:hidden]
103
103
  frame args do
104
104
  card_form action, form_opts do
105
105
  output(yield args)
File without changes
@@ -85,6 +85,16 @@ describe Card::Content::Chunk::Include, 'Inclusion' do
85
85
  expect(options[:view]).to eq('link')
86
86
  expect(options[:items][:view]).to eq('name')
87
87
  end
88
+
89
+ it '#each_option should work' do
90
+ @chunk = '{{}}'
91
+ expect { |b| instance.send(:each_option, '', &b) }.not_to yield_control
92
+ expect { |b| instance.send(:each_option, nil, &b) }.not_to yield_control
93
+ expect { |b| instance.send(:each_option, 'a:b;c:4', &b) }
94
+ .to yield_successive_args(%w(a b), %w(c 4))
95
+ expect { |b| instance.send(:each_option, 'd:b;e:4; ', &b) }
96
+ .to yield_successive_args(%w(d b), %w(e 4))
97
+ end
88
98
  end
89
99
 
90
100
  context 'rendering' do
@@ -189,15 +199,5 @@ describe Card::Content::Chunk::Include, 'Inclusion' do
189
199
  assert_select 'div[class~="card-content"]', 'Pooey'
190
200
  end
191
201
  end
192
-
193
- # FIXME: should move code and test to core_ext or some such
194
- it 'Hash.new_from_semicolon_attr_list should work' do
195
- expect(Hash.new_from_semicolon_attr_list('')).to eq({})
196
- expect(Hash.new_from_semicolon_attr_list(nil)).to eq({})
197
- expect(Hash.new_from_semicolon_attr_list('a:b;c:4'))
198
- .to eq(a: 'b', c: '4')
199
- expect(Hash.new_from_semicolon_attr_list('d:b;e:4; '))
200
- .to eq(d: 'b', e: '4')
201
- end
202
202
  end
203
203
  end
@@ -0,0 +1,15 @@
1
+ describe Hash do
2
+ describe 'new_nested' do
3
+ it 'creates nested hashes' do
4
+ nested_hash = Hash.new_nested Hash, Hash
5
+ expect(nested_hash[:a]).to be_instance_of Hash
6
+ expect(nested_hash[:a][:b]).to be_instance_of Hash
7
+ expect(nested_hash[:d][:c]).to be_instance_of Hash
8
+ end
9
+
10
+ it 'creates set in hash' do
11
+ nested_hash = Hash.new_nested ::Set
12
+ expect(nested_hash[:a]).to be_instance_of ::Set
13
+ end
14
+ end
15
+ end
@@ -100,7 +100,7 @@ describe Card::StageDirector do
100
100
  end
101
101
  let(:create_card_with_junction) do
102
102
  Card.create name: '1+2',
103
- subcards: { '11' => 'A'}
103
+ subcards: { '11' => 'A' }
104
104
  end
105
105
  let(:preorder) { %w(1 11 111 12 121) }
106
106
  let(:postorder) { %w(111 11 121 12 1) }
@@ -312,6 +312,30 @@ describe Card::StageDirector do
312
312
  expect(Card['main1+main2+sub2+sub3'].content).to eq('content')
313
313
  end
314
314
  end
315
+
316
+ it 'adds subsubcard to correct subdirector' do
317
+ Card::Auth.as_bot do
318
+ in_stage :prepare_to_store,
319
+ on: :create,
320
+ trigger: -> { Card.create! name: 'main' } do
321
+ case name
322
+ when 'main'
323
+ add_subcard 'subby', '+sub2' => {
324
+ subcards: { 'AARGH' => { '+sub4' => 'more content' } }
325
+ }
326
+ in_subdirectors = director.subdirectors.any? do |subdir|
327
+ subdir.card.name == 'AARGH'
328
+ end
329
+ expect(in_subdirectors).to be_falsey
330
+ when 'subby+sub2'
331
+ in_subsubdirectors = director.subdirectors.any? do |subdir|
332
+ subdir.card.name == 'AARGH'
333
+ end
334
+ expect(in_subsubdirectors).to be_truthy
335
+ end
336
+ end
337
+ end
338
+ end
315
339
  end
316
340
 
317
341
  describe 'creating and updating cards in stages' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: card
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.18.4
4
+ version: 1.18.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ethan McCutchen
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2016-04-08 00:00:00.000000000 Z
14
+ date: 2016-05-07 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: smartname
@@ -45,16 +45,16 @@ dependencies:
45
45
  name: carrierwave
46
46
  requirement: !ruby/object:Gem::Requirement
47
47
  requirements:
48
- - - "~>"
48
+ - - "<="
49
49
  - !ruby/object:Gem::Version
50
- version: '0.10'
50
+ version: 0.11.0
51
51
  type: :runtime
52
52
  prerelease: false
53
53
  version_requirements: !ruby/object:Gem::Requirement
54
54
  requirements:
55
- - - "~>"
55
+ - - "<="
56
56
  - !ruby/object:Gem::Version
57
- version: '0.10'
57
+ version: 0.11.0
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: htmlentities
60
60
  requirement: !ruby/object:Gem::Requirement
@@ -242,7 +242,13 @@ files:
242
242
  - README_Developers.rdoc
243
243
  - VERSION
244
244
  - card.gemspec
245
- - config/initializers/01_init_ruby_extensions.rb
245
+ - config/initializers/01_core_extensions/array.rb
246
+ - config/initializers/01_core_extensions/hash.rb
247
+ - config/initializers/01_core_extensions/module.rb
248
+ - config/initializers/01_core_extensions/object.rb
249
+ - config/initializers/02_extensions/kaminari.rb
250
+ - config/initializers/core_extensions.rb
251
+ - config/initializers/extensions.rb
246
252
  - config/initializers/inflections.rb
247
253
  - config/initializers/mime_types.rb
248
254
  - config/initializers/notification.rb
@@ -395,7 +401,6 @@ files:
395
401
  - lib/card/content.rb
396
402
  - lib/card/content/chunk.rb
397
403
  - lib/card/content/parser.rb
398
- - lib/card/core_ext.rb
399
404
  - lib/card/core_migration.rb
400
405
  - lib/card/diff.rb
401
406
  - lib/card/diff/lcs.rb
@@ -415,13 +420,21 @@ files:
415
420
  - lib/card/query.rb
416
421
  - lib/card/query/attributes.rb
417
422
  - lib/card/query/clause.rb
423
+ - lib/card/query/conjunctions.rb
424
+ - lib/card/query/helpers.rb
425
+ - lib/card/query/interpretation.rb
418
426
  - lib/card/query/join.rb
419
427
  - lib/card/query/reference.rb
428
+ - lib/card/query/relational_attributes.rb
429
+ - lib/card/query/sorting.rb
420
430
  - lib/card/query/sql_statement.rb
421
431
  - lib/card/query/value.rb
422
432
  - lib/card/reference.rb
423
433
  - lib/card/set.rb
424
434
  - lib/card/set/event.rb
435
+ - lib/card/set/format.rb
436
+ - lib/card/set/helpers.rb
437
+ - lib/card/set/loader.rb
425
438
  - lib/card/set/trait.rb
426
439
  - lib/card/set_pattern.rb
427
440
  - lib/card/simplecov_helper.rb
@@ -736,6 +749,7 @@ files:
736
749
  - mod/05_standard/set/self/admin_info.rb
737
750
  - mod/05_standard/set/self/alerts.rb
738
751
  - mod/05_standard/set/self/all.rb
752
+ - mod/05_standard/set/self/codenames.rb
739
753
  - mod/05_standard/set/self/foot.rb
740
754
  - mod/05_standard/set/self/head.rb
741
755
  - mod/05_standard/set/self/navbox.rb
@@ -990,6 +1004,7 @@ files:
990
1004
  - mod/06_bootstrap/set/self/smartmenu_css.rb
991
1005
  - mod/06_bootstrap/set/self/smartmenu_js.rb
992
1006
  - mod/06_bootstrap/spec/set/all/bootstrap/form_spec.rb
1007
+ - spec/config/initializers/core_extensions_spec.rb
993
1008
  - spec/lib/card/action_spec.rb
994
1009
  - spec/lib/card/auth_spec.rb
995
1010
  - spec/lib/card/cache_spec.rb
@@ -1223,6 +1238,7 @@ signing_key:
1223
1238
  specification_version: 4
1224
1239
  summary: an atomic, set-driven content engine
1225
1240
  test_files:
1241
+ - spec/config/initializers/core_extensions_spec.rb
1226
1242
  - spec/lib/card/action_spec.rb
1227
1243
  - spec/lib/card/auth_spec.rb
1228
1244
  - spec/lib/card/cache_spec.rb
@@ -1250,3 +1266,4 @@ test_files:
1250
1266
  - spec/models/card/validation_spec.rb
1251
1267
  - spec/models/card_spec.rb
1252
1268
  - spec/spec_helper.rb
1269
+ has_rdoc:
@@ -1,3 +0,0 @@
1
- # -*- encoding : utf-8 -*-
2
-
3
- require 'card/core_ext'
@@ -1,107 +0,0 @@
1
- class Object
2
- # FIXME: move this, mixin, don't extend Object
3
- def deep_clone
4
- case self
5
- when Fixnum, Bignum, Float, NilClass, FalseClass, TrueClass, Symbol
6
- klone = self
7
- when Hash
8
- klone = clone
9
- each { |k, v| klone[k] = v.deep_clone }
10
- when Array
11
- klone = clone
12
- klone.clear
13
- each { |v| klone << v.deep_clone }
14
- else
15
- klone = clone
16
- end
17
- klone.instance_variables.each do |v|
18
- klone.instance_variable_set(v,
19
- klone.instance_variable_get(v).deep_clone)
20
- end
21
- klone
22
- end
23
-
24
- def send_unless method, *args, &_block
25
- (block_given? ? yield : self) || send(method, *args)
26
- end
27
-
28
- def send_if method, *args, &_block
29
- (block_given? ? yield : self) && send(method, *args)
30
- end
31
-
32
- def to_name
33
- Card::Name.new self
34
- end
35
-
36
- def to_viewname
37
- Card::ViewName.new self
38
- end
39
- end
40
-
41
- class Module
42
- RUBY_VERSION_18 = !!(RUBY_VERSION =~ /^1\.8/)
43
-
44
- def const_get_if_defined const
45
- args = RUBY_VERSION_18 ? [const] : [const, false]
46
- const_get *args if const_defined? *args
47
- end
48
-
49
- def const_get_or_set const
50
- const_get_if_defined(const) || const_set(const, yield)
51
- end
52
- end
53
-
54
- class Hash
55
- # FIXME: this is too ugly and narrow for a core extension.
56
- class << self
57
- def new_from_semicolon_attr_list attr_string
58
- return {} if attr_string.blank?
59
- attr_string.strip.split(';').inject({}) do |result, pair|
60
- value, key = pair.split(':').reverse
61
- key ||= 'view'
62
- key.strip!; value.strip!
63
- result[key.to_sym] = value
64
- result
65
- end
66
- end
67
- end
68
- end
69
-
70
- class Array
71
- def to_pointer_content
72
- map do |item|
73
- "[[#{item}]]"
74
- end.join "\n"
75
- end
76
- end
77
-
78
- class Kaminari::Helpers::Tag
79
- def page_url_for page
80
- p = params_for(page)
81
- p.delete :controller
82
- p.delete :action
83
- card = Card[p.delete('id')]
84
- card.format.path p
85
- end
86
-
87
- private
88
-
89
- def params_for page
90
- page_params = Rack::Utils.parse_nested_query("#{@param_name}=#{page}")
91
- page_params = @params.with_indifferent_access.deep_merge(page_params)
92
-
93
- if Kaminari.config.respond_to?(:params_on_first_page) && !Kaminari.config.params_on_first_page && page <= 1
94
- # This converts a hash:
95
- # from: {other: "params", page: 1}
96
- # to: {other: "params", page: nil}
97
- # (when @param_name == "page")
98
- #
99
- # from: {other: "params", user: {name: "yuki", page: 1}}
100
- # to: {other: "params", user: {name: "yuki", page: nil}}
101
- # (when @param_name == "user[page]")
102
- @param_name.to_s.scan(/\w+/)[0..-2].inject(page_params) { |h, k| h[k] }[$&] = nil
103
- end
104
-
105
- page_params
106
- end
107
- end