card 1.93.3 → 1.93.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (160) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/db/migrate/20170908114452_increase_text_size_for_delayed_jobs.rb +9 -0
  4. data/db/migrate_core_cards/data/cards/*header +2 -2
  5. data/lib/card/format/nest.rb +12 -5
  6. data/lib/card/format/nest/fetch.rb +1 -2
  7. data/lib/card/format/render.rb +2 -2
  8. data/lib/card/model/save_helper.rb +1 -1
  9. data/lib/card/set/format/haml_views.rb +7 -3
  10. data/lib/card/subcards.rb +27 -228
  11. data/lib/card/subcards/add.rb +121 -0
  12. data/lib/card/subcards/relate.rb +27 -0
  13. data/lib/card/subcards/remove.rb +42 -0
  14. data/lib/card/tasks/card/create.rake +35 -132
  15. data/lib/card/tasks/card/file_card_creator.rb +25 -0
  16. data/lib/card/tasks/card/file_card_creator/abstract_file_card.rb +44 -0
  17. data/lib/card/tasks/card/file_card_creator/abstract_file_card/migration_file.rb +49 -0
  18. data/lib/card/tasks/card/file_card_creator/abstract_file_card/ruby_file.rb +30 -0
  19. data/lib/card/tasks/card/file_card_creator/abstract_file_card/source_file.rb +36 -0
  20. data/lib/card/tasks/card/file_card_creator/haml_card.rb +42 -0
  21. data/lib/card/tasks/card/file_card_creator/output_helper.rb +50 -0
  22. data/lib/card/tasks/card/file_card_creator/script_card.rb +33 -0
  23. data/lib/card/tasks/card/file_card_creator/style_card.rb +25 -0
  24. data/lib/generators/card/template/template_generator.rb +1 -1
  25. data/mod/account/set/self/account_links.rb +1 -1
  26. data/mod/basic_formats/set/all/all_csv.rb +63 -0
  27. data/mod/basic_formats/set/all/json.rb +4 -1
  28. data/mod/bootstrap/db/migrate_cards/20170719163733_update_bootswatch_themes_to_4_beta.rb +5 -2
  29. data/mod/carrierwave/set/abstract/attachment.rb +1 -2
  30. data/mod/core/set/abstract/haml_file.rb +20 -0
  31. data/mod/core/set/all/chunk.rb +125 -0
  32. data/mod/core/set/all/collection.rb +2 -351
  33. data/mod/core/set/all/content.rb +26 -7
  34. data/mod/core/set/all/extended.rb +45 -0
  35. data/mod/core/set/all/haml.rb +3 -7
  36. data/mod/core/set/all/item.rb +92 -0
  37. data/mod/core/set/all/name.rb +36 -0
  38. data/mod/core/set/all/subcards.rb +21 -12
  39. data/mod/core/set/all/tabs.rb +50 -0
  40. data/mod/core/set/all/trash.rb +4 -0
  41. data/mod/core/spec/set/all/chunk_spec.rb +45 -0
  42. data/mod/core/spec/set/all/collection_spec.rb +6 -6
  43. data/mod/history/set/all/action_view.rb +1 -1
  44. data/mod/machines/lib/javascript/decko.js.coffee +3 -0
  45. data/mod/pointer/set/abstract/02_pointer/edit.rb +0 -2
  46. data/mod/search/set/abstract/search.rb +1 -1
  47. data/mod/search/set/all/filter.rb +0 -2
  48. data/mod/search/template/all/filter/_filter_input.haml +1 -1
  49. data/mod/search/template/all/filter/filter_form.haml +1 -1
  50. data/mod/standard/set/all/rich_html/editing.rb +1 -1
  51. data/mod/standard/set/all/rich_html/form.rb +6 -7
  52. data/mod/standard/set/all/rich_html/menu.rb +2 -3
  53. data/mod/standard/set/all/rich_html/toolbar.rb +3 -4
  54. data/mod/standard/set/type/cardtype.rb +1 -1
  55. data/mod/standard/spec/set/all/rich_html/editing_spec.rb +15 -4
  56. data/mod/tinymce_editor/db/migrate_cards/{20171113233150_update_tinymce_config.rb → 20171113233151_update_tinymce_config.rb} +1 -0
  57. metadata +25 -161
  58. data/.rspec +0 -4
  59. data/card.gemspec +0 -87
  60. data/db/seed/test/fixtures/.gitkeep +0 -0
  61. data/mod/bootstrap/vendor/bootstrap/.babelrc.js +0 -16
  62. data/mod/bootstrap/vendor/bootstrap/.editorconfig +0 -17
  63. data/mod/bootstrap/vendor/bootstrap/.eslintignore +0 -3
  64. data/mod/bootstrap/vendor/bootstrap/.gitattributes +0 -16
  65. data/mod/bootstrap/vendor/bootstrap/.github/CONTRIBUTING.md +0 -252
  66. data/mod/bootstrap/vendor/bootstrap/.github/ISSUE_TEMPLATE.md +0 -22
  67. data/mod/bootstrap/vendor/bootstrap/.gitignore +0 -46
  68. data/mod/bootstrap/vendor/bootstrap/.hound.yml +0 -19
  69. data/mod/bootstrap/vendor/bootstrap/.houndignore +0 -4
  70. data/mod/bootstrap/vendor/bootstrap/.travis.yml +0 -32
  71. data/mod/bootstrap/vendor/bootstrap/build/.htmllintrc +0 -19
  72. data/mod/bootstrap/vendor/bootstrap/build/.stylelintrc +0 -248
  73. data/mod/bootstrap/vendor/bootstrap/docs/4.0/examples/.stylelintrc +0 -12
  74. data/mod/bootstrap/vendor/bootstrap/js/.eslintrc.json +0 -240
  75. data/mod/bootstrap/vendor/bootstrap/js/tests/.eslintrc.json +0 -46
  76. data/mod/bootstrap/vendor/bootswatch/.gitignore +0 -7
  77. data/mod/bootstrap/vendor/bootswatch/.npmignore +0 -12
  78. data/mod/bootstrap/vendor/bootswatch/.travis.yml +0 -21
  79. data/mod/bootstrap/vendor/bootswatch/docs/.nojekyll +0 -0
  80. data/mod/bootstrap/vendor/bootswatch/docs/2/.travis.yml +0 -15
  81. data/mod/bootstrap/vendor/bootswatch/docs/2/bower_components/bootstrap/.bower.json +0 -20
  82. data/mod/bootstrap/vendor/bootswatch/docs/2/bower_components/bootstrap/.gitignore +0 -37
  83. data/mod/bootstrap/vendor/bootswatch/docs/2/bower_components/bootstrap/.travis.yml +0 -3
  84. data/mod/bootstrap/vendor/bootswatch/docs/2/bower_components/bootstrap/js/.jshintrc +0 -12
  85. data/mod/bootstrap/vendor/bootswatch/docs/2/bower_components/jquery/.bower.json +0 -20
  86. data/mod/bootstrap/vendor/bootswatch/docs/2/bower_components/jquery/.gitignore +0 -1
  87. data/mod/bootstrap/vendor/bootswatch/docs/2/swatchmaker/.gitignore +0 -1
  88. data/mod/bootstrap/vendor/bootswatch/docs/3/bower_components/bootstrap-sass-official/.bower.json +0 -45
  89. data/mod/bootstrap/vendor/bootswatch/docs/3/bower_components/bootstrap/.bower.json +0 -44
  90. data/mod/bootstrap/vendor/bootswatch/docs/3/bower_components/bootstrap/grunt/.jshintrc +0 -7
  91. data/mod/bootstrap/vendor/bootswatch/docs/3/bower_components/bootstrap/js/.jscsrc +0 -42
  92. data/mod/bootstrap/vendor/bootswatch/docs/3/bower_components/bootstrap/js/.jshintrc +0 -15
  93. data/mod/bootstrap/vendor/bootswatch/docs/3/bower_components/bootstrap/less/.csscomb.json +0 -304
  94. data/mod/bootstrap/vendor/bootswatch/docs/3/bower_components/bootstrap/less/.csslintrc +0 -19
  95. data/mod/bootstrap/vendor/bootswatch/docs/3/bower_components/font-awesome/.bower.json +0 -14
  96. data/mod/bootstrap/vendor/bootswatch/docs/3/bower_components/font-awesome/.gitignore +0 -32
  97. data/mod/bootstrap/vendor/bootswatch/docs/3/bower_components/html5shiv/.bower.json +0 -25
  98. data/mod/bootstrap/vendor/bootswatch/docs/3/bower_components/jquery/.bower.json +0 -38
  99. data/mod/bootstrap/vendor/bootswatch/docs/3/bower_components/respond/.bower.json +0 -20
  100. data/mod/bootstrap/vendor/select2/.editorconfig +0 -6
  101. data/mod/bootstrap/vendor/select2/.github/CONTRIBUTING.md +0 -204
  102. data/mod/bootstrap/vendor/select2/.github/ISSUE_TEMPLATE.md +0 -46
  103. data/mod/bootstrap/vendor/select2/.github/PULL_REQUEST_TEMPLATE.md +0 -13
  104. data/mod/bootstrap/vendor/select2/.gitignore +0 -3
  105. data/mod/bootstrap/vendor/select2/.jshintignore +0 -4
  106. data/mod/bootstrap/vendor/select2/.jshintrc +0 -25
  107. data/mod/bootstrap/vendor/select2/.travis.yml +0 -22
  108. data/script/fetch_bootswatch_themes.rb +0 -38
  109. data/spec/config/initializers/core_extensions_spec.rb +0 -47
  110. data/spec/config/initializers/patches/active_job_spec.rb +0 -7
  111. data/spec/lib/card/action_spec.rb +0 -15
  112. data/spec/lib/card/auth_spec.rb +0 -58
  113. data/spec/lib/card/cache_spec.rb +0 -116
  114. data/spec/lib/card/chunk_spec.rb +0 -18
  115. data/spec/lib/card/codename_spec.rb +0 -66
  116. data/spec/lib/card/content_spec.rb +0 -428
  117. data/spec/lib/card/diff_spec.rb +0 -208
  118. data/spec/lib/card/format/nest_spec.rb +0 -13
  119. data/spec/lib/card/format/render_spec.rb +0 -26
  120. data/spec/lib/card/format_spec.rb +0 -117
  121. data/spec/lib/card/i18n_spec.rb +0 -24
  122. data/spec/lib/card/loader/Modfile +0 -2
  123. data/spec/lib/card/loader_spec.rb +0 -98
  124. data/spec/lib/card/migration/import_spec.rb +0 -80
  125. data/spec/lib/card/mod/loader/mod_dirs.rb +0 -8
  126. data/spec/lib/card/mod/loader/set_loader_spec.rb +0 -19
  127. data/spec/lib/card/mod/loader/set_pattern_loader_spec.rb +0 -19
  128. data/spec/lib/card/name/fields_and_traits_spec.rb +0 -18
  129. data/spec/lib/card/name_spec.rb +0 -70
  130. data/spec/lib/card/query/sorting_spec.rb +0 -68
  131. data/spec/lib/card/query_spec.rb +0 -574
  132. data/spec/lib/card/reference_spec.rb +0 -212
  133. data/spec/lib/card/set/event_spec.rb +0 -22
  134. data/spec/lib/card/set/trait_spec.rb +0 -80
  135. data/spec/lib/card/set_pattern_spec.rb +0 -59
  136. data/spec/lib/card/set_spec.rb +0 -89
  137. data/spec/lib/card/stage_director_spec.rb +0 -482
  138. data/spec/lib/card/subcards_spec.rb +0 -177
  139. data/spec/lib/card/success_spec.rb +0 -148
  140. data/spec/lib/card/view_cache_spec.rb +0 -27
  141. data/spec/mailers/mailer_spec.rb +0 -62
  142. data/spec/models/card/create_spec.rb +0 -119
  143. data/spec/models/card/trash_spec.rb +0 -189
  144. data/spec/models/card_spec.rb +0 -136
  145. data/spec/spec_helper.rb +0 -45
  146. data/spec/support/card_spec_helper.rb +0 -74
  147. data/spec/support/card_spec_loader.rb +0 -112
  148. data/spec/support/helper/card_helper.rb +0 -58
  149. data/spec/support/helper/event_helper.rb +0 -94
  150. data/spec/support/helper/render_helper.rb +0 -44
  151. data/spec/support/helper/save_helper.rb +0 -30
  152. data/spec/support/helper/set_helper.rb +0 -80
  153. data/spec/support/matchers/card_matchers.rb +0 -160
  154. data/spec/support/matchers/expectations.rb +0 -5
  155. data/spec/support/matchers/file_matchers.rb +0 -71
  156. data/spec/support/matchers/html_matchers.rb +0 -29
  157. data/spec/support/matchers/negated_matchers.rb +0 -2
  158. data/spec/support/simplecov_helper.rb +0 -70
  159. data/spec/support/test_mods/mod1/set/all/test_set.rb +0 -3
  160. data/spec/support/test_mods/mod2/set_pattern/test_pattern.rb +0 -0
@@ -1,80 +0,0 @@
1
- # -*- encoding : utf-8 -*-
2
-
3
- describe Card::Migration::Import do
4
- let(:path) { Card::Migration.data_path }
5
- let(:importer) { Card::Migration::Import.new path }
6
-
7
- def card_meta_path
8
- Card::Migration::Import::ImportData.new(path).instance_variable_get("@path")
9
- end
10
-
11
- def card_content_dir
12
- Card::Migration::Import::ImportData.new(path).instance_variable_get("@card_content_dir")
13
- end
14
-
15
- def meta_data
16
- YAML.load_file(card_meta_path).deep_symbolize_keys
17
- end
18
-
19
- def content_path filename
20
- File.join(card_content_dir, filename)
21
- end
22
-
23
- def content_data_file filename
24
- File.read content_path filename
25
- end
26
-
27
- before(:each) do
28
- FileUtils.rm card_meta_path if File.exist? card_meta_path
29
- FileUtils.rm_rf card_content_dir if Dir.exist? card_content_dir
30
- end
31
-
32
- describe ".add_remote" do
33
- it "adds remote to yml file" do
34
- importer.add_remote "test", "url"
35
- remotes = meta_data[:remotes]
36
- expect(remotes[:test]).to eq "url"
37
- end
38
- end
39
-
40
- describe ".pull" do
41
- it "saves card attributes" do
42
- importer.pull "A"
43
- cards = meta_data[:cards]
44
- expect(cards).to be_instance_of(Array)
45
- expect(cards.first[:name]).to eq "A"
46
- expect(cards.first[:type]).to eq "Basic"
47
- end
48
-
49
- it "saves card content" do
50
- importer.pull "A"
51
- expect(content_data_file("a")).to eq "Alpha [[Z]]"
52
- end
53
-
54
- context "called with deep: true" do
55
- it "saves nested card" do
56
- importer.pull "B", deep: true
57
- expect(content_data_file("z")).to eq "I'm here to be referenced to"
58
- end
59
-
60
- it "does not save linked card" do
61
- importer.pull "A", deep: true
62
- expect(File.exist?(content_path("z"))).to be_falsey
63
- end
64
-
65
- it "saves pointer items" do
66
- importer.pull "Fruit+*type+*create", deep: true
67
- expect(File.exist?(content_path("anyone"))).to be_truthy
68
- end
69
- end
70
- end
71
-
72
- describe ".merge" do
73
- it "updates card content" do
74
- importer.pull "A"
75
- File.write content_path("a"), "test"
76
- importer.merge
77
- expect(Card["A"].content).to eq "test"
78
- end
79
- end
80
- end
@@ -1,8 +0,0 @@
1
-
2
- describe Card::Mod::Dirs do
3
- it 'loads mods from Modfile' do
4
- path = File.expand_path "..", __FILE__
5
- tg = Card::Mod::Dirs.new path
6
- expect(tg.mods).to eq %w(mod1 mod2)
7
- end
8
- end
@@ -1,19 +0,0 @@
1
- # -*- encoding : utf-8 -*-
2
-
3
- RSpec.describe Card::Mod::Loader::SetLoader do
4
- let(:mod_dirs) do
5
- path = File.expand_path "../../../../../support/test_mods", __FILE__
6
- Card::Mod::Dirs.new path
7
- end
8
-
9
- it 'initializes the load strategy' do
10
- expect(Card::Mod::LoadStrategy::Eval).to receive(:new).with(mod_dirs, instance_of(described_class))
11
- described_class.new(:eval, mod_dirs)
12
- end
13
-
14
- it "load mods" do
15
- described_class.new(:eval, mod_dirs).load
16
- expect(Card::Set.const_defined?("All::TestSet")).to be_truthy
17
- expect(Card.take.test_method).to eq "works"
18
- end
19
- end
@@ -1,19 +0,0 @@
1
- # -*- encoding : utf-8 -*-
2
-
3
- RSpec.describe Card::Mod::Loader::SetPatternLoader do
4
- let(:mod_dirs) do
5
- path = File.expand_path "../../../../../support/test_mods", __FILE__
6
- puts path
7
- Card::Mod::Dirs.new path
8
- end
9
-
10
- it 'initializes the load strategy' do
11
- expect(Card::Mod::LoadStrategy::Eval).to receive(:new).with(mod_dirs, instance_of(described_class))
12
- described_class.new :eval, mod_dirs
13
- end
14
-
15
- it "load mods" do
16
- described_class.new(:eval, mod_dirs).load
17
- expect(Card::Set.const_defined?("TestPattern")).to be_truthy
18
- end
19
- end
@@ -1,18 +0,0 @@
1
- # -*- encoding : utf-8 -*-
2
-
3
- describe Card::Name do
4
- describe "field_of?" do
5
- it "should identify fields" do
6
- expect("A+B" .to_name.field_of? "A" ).to be_truthy
7
- expect("A+B" .to_name.field_of? "B" ).to be_falsey
8
- expect("A+B" .to_name.field_of? "A+B").to be_falsey
9
- expect("A+B" .to_name.field_of? "A+C").to be_falsey
10
- expect("A+B+C".to_name.field_of? "A+B").to be_truthy
11
- expect("+B" .to_name.field_of? "A" ).to be_truthy
12
- expect("+B" .to_name.field_of? "A+B").to be_truthy
13
- expect("+B" .to_name.field_of? "" ).to be_truthy
14
- expect("+B" .to_name.field_of? nil ).to be_truthy
15
-
16
- end
17
- end
18
- end
@@ -1,70 +0,0 @@
1
- # -*- encoding : utf-8 -*-
2
-
3
- RSpec.describe Card::Name do
4
- describe "#valid" do
5
- it "rejects long names" do
6
- card = Card.new
7
- card.name = "1" * 256
8
- expect(card).not_to be_valid
9
- end
10
- end
11
-
12
- describe "Cardnames star handling" do
13
- it "recognizes star cards" do
14
- expect("*a".to_name.star?).to be_truthy
15
- end
16
-
17
- it "doesn't recognize star cards with plusses" do
18
- expect("*a+*b".to_name.star?).to be_falsey
19
- end
20
-
21
- it "recognizes rstar cards" do
22
- expect("a+*a".to_name.rstar?).to be_truthy
23
- end
24
-
25
- it "doesn't recognize star cards as rstar" do
26
- expect("*a".to_name.rstar?).to be_falsey
27
- end
28
-
29
- it "doesn't recognize non-star or star left" do
30
- expect("*a+a".to_name.rstar?).to be_falsey
31
- end
32
- end
33
-
34
- describe "trait_name?" do
35
- it "returns true for content codename" do
36
- expect("bazoinga+*right+*structure".to_name.trait_name?(:structure)).to(
37
- be_truthy
38
- )
39
- end
40
-
41
- it "handles arrays" do
42
- structure =
43
- "bazoinga+*right+*structure".to_name.trait_name?(:structure, :default)
44
- expect(structure).to be_truthy
45
- end
46
-
47
- it "returns false for non-template" do
48
- structure = "bazoinga+*right+nontent".to_name.trait_name?(:structure)
49
- expect(structure).to be_falsey
50
- end
51
- end
52
-
53
- describe "#absolute" do
54
- it "does session user substitution" do
55
- expect("_user".to_name.absolute("A")).to eq(Card::Auth.current.name)
56
- Card::Auth.as_bot do
57
- expect("_user".to_name.absolute("A")).to eq(Card::Auth.current.name)
58
- end
59
- end
60
- end
61
-
62
- describe "part creation" do
63
- it "creates parts" do
64
- Card::Auth.as_bot do
65
- Card.create name: "left+right"
66
- end
67
- expect(Card.fetch("right")).to be_truthy
68
- end
69
- end
70
- end
@@ -1,68 +0,0 @@
1
- describe Card::Query, "sorting" do
2
- subject do
3
- Card::Query.run @query.reverse_merge return: :name, sort: :name
4
- end
5
-
6
- it "sorts by create" do
7
- Card.create! name: "classic bootstrap skin head"
8
- # classic skin head is created more recently than classic skin,
9
- # which is in the seed data
10
- @query = { sort: "create", name: [:match, "classic bootstrap skin"] }
11
- is_expected.to eq(
12
- ["classic bootstrap skin", "classic bootstrap skin head"]
13
- )
14
- end
15
-
16
- it "sorts by name" do
17
- @query = { name: %w(in B Z A Y C X), sort: "name", dir: "desc" }
18
- is_expected.to eq(%w(Z Y X C B A))
19
- end
20
-
21
- it "sorts by content" do
22
- @query = { name: %w(in Z T A), sort: "content" }
23
- is_expected.to eq(%w(A Z T))
24
- end
25
-
26
- it "plays nice with match" do
27
- @query = { match: "Z", type: "Basic", sort: "content" }
28
- is_expected.to eq(%w(A B Z A+B+Y+Z))
29
- end
30
-
31
- it "sorts by plus card content" do
32
- Card::Auth.as_bot do
33
- c = Card.fetch("Setting+*self+*table of contents")
34
- c.content = "10"
35
- c.save
36
- Card.create! name: "Basic+*type+*table of contents", content: "3"
37
-
38
- @query = {
39
- right_plus: "*table of contents",
40
- sort: { right: "*table_of_contents" },
41
- sort_as: "integer"
42
- }
43
- is_expected.to eq(%w(*all Basic+*type Setting+*self))
44
- end
45
- end
46
-
47
- it "sorts by count" do
48
- Card::Auth.as_bot do
49
- @query = {
50
- name: [:in, "*always", "*never", "*edited"],
51
- sort: { right: "*follow", item: "referred_to", return: "count" }
52
- }
53
- is_expected.to eq(["*never", "*edited", "*always"])
54
- end
55
- end
56
-
57
- # it 'sorts by update' do
58
- # # do this on a restricted set so it won't change every time we
59
- # # add a card..
60
- # Card::Query.run(
61
- # match: 'two', sort: 'update', dir: 'desc'
62
- # ).map(&:name).should == ['One+Two+Three', 'One+Two','Two','Joe User']
63
- # Card['Two'].update_attributes! content: 'new bar'
64
- # Card::Query.run(
65
- # match: 'two', sort: 'update', dir: 'desc'
66
- # ).map(&:name).should == ['Two','One+Two+Three', 'One+Two','Joe User']
67
- # end
68
- end
@@ -1,574 +0,0 @@
1
- # -*- encoding : utf-8 -*-
2
-
3
- RSpec.describe Card::Query do
4
- A_JOINEES = %w(B C D E F).freeze
5
- CARDS_MATCHING_TWO = ["Joe User", "One+Two", "One+Two+Three", "Two"].freeze
6
-
7
- subject do
8
- Card::Query.run @query.reverse_merge return: :name, sort: :name
9
- end
10
-
11
- it "does not alter original statement" do
12
- @query = { right_plus: { name: %w(in tag source) } }
13
- query_clone = @query.deep_clone
14
- subject # runs query
15
- expect(query_clone).to eq(@query)
16
- end
17
-
18
- describe "append" do
19
- it "finds real cards" do
20
- @query = {
21
- name: [:in, "C", "D", "F"],
22
- append: "A"
23
- }
24
- is_expected.to eq(%w(C+A D+A F+A))
25
- end
26
-
27
- it "absolutizes names" do
28
- @query = {
29
- name: [:in, "C", "D", "F"],
30
- append: "_right",
31
- context: "B+A"
32
- }
33
- is_expected.to eq(%w(C+A D+A F+A))
34
- end
35
-
36
- it "finds virtual cards" do
37
- @query = {
38
- name: [:in, "C", "D"],
39
- append: "*plus cards"
40
- }
41
- is_expected.to eq(["C+*plus cards", "D+*plus cards"])
42
- end
43
- end
44
-
45
- describe "in" do
46
- example "content option" do
47
- @query = { in: %w(AlphaBeta Theta) }
48
- is_expected.to eq(%w(A+B T))
49
- end
50
-
51
- it "finds the same thing in full syntax" do
52
- @query = { content: [:in, "Theta", "AlphaBeta"] }
53
- is_expected.to eq(%w(A+B T))
54
- end
55
-
56
- example "type option" do
57
- @query = { type: [:in, "Cardtype E", "Cardtype F"] }
58
- is_expected.to eq(%w(type-e-card type-f-card))
59
- end
60
- end
61
-
62
- describe "member_of" do
63
- it "finds members" do
64
- @query = { member_of: "r1" }
65
- is_expected.to eq(%w(u1 u2 u3))
66
- end
67
- end
68
-
69
- describe "member" do
70
- it "finds roles" do
71
- @query = { member: { match: "u1" } }
72
- is_expected.to eq(%w(r1 r2 r3))
73
- end
74
- end
75
-
76
- describe "not" do
77
- it "excludes cards matching not criteria" do
78
- Card::Auth.as_bot
79
- @query = { plus: "A", not: { plus: "A+B" } }
80
- is_expected.to eq(%w(B D E F))
81
- end
82
- end
83
-
84
- describe "multiple values" do
85
- it "handles :all as the first element of an Array" do
86
- @query = { member_of: [:all, { name: "r1" }, { key: "r2" }] }
87
- is_expected.to eq(%w(u1 u2))
88
- end
89
-
90
- it "handles act like :all by default" do
91
- @query = { member_of: [{ name: "r1" }, { key: "r2" }] }
92
- is_expected.to eq(%w(u1 u2))
93
- end
94
-
95
- it "handles :any as the first element of an Array" do
96
- @query = { member_of: [:any, { name: "r1" }, { key: "r2" }] }
97
- is_expected.to eq(%w(u1 u2 u3))
98
- end
99
-
100
- it "handles :any as a relationship" do
101
- @query = { member_of: { any: [{ name: "r1" }, { key: "r2" }] } }
102
- is_expected.to eq(%w(u1 u2 u3))
103
- end
104
-
105
- it "handles explicit conjunctions in plus_relational keys" do
106
- @query = { right_plus: [:all, "e", "c"] }
107
- is_expected.to eq(%w(A))
108
- end
109
-
110
- it "handles multiple values for right_part in compound relations" do
111
- @query = { right_plus: [["e", {}], "c"] }
112
- is_expected.to eq(%w(A)) # first element is array
113
- end
114
-
115
- it "does not interpret simple arrays as multi values for plus" do
116
- @query = { right_plus: %w(e c) }
117
- is_expected.to eq([]) # NOT interpreted as multi-value
118
- end
119
-
120
- it "handles :and for references" do
121
- @query = { refer_to: [:and, "a", "b"] }
122
- is_expected.to eq(%w(Y))
123
- end
124
-
125
- it "handles :or for references" do
126
- @query = { refer_to: [:or, "b", "z"] }
127
- is_expected.to eq(%w(A B Y))
128
- end
129
-
130
- it "handles treat simple arrays like :all for references" do
131
- @query = { refer_to: %w(A T) }
132
- is_expected.to eq(%w(X Y))
133
- end
134
- end
135
-
136
- describe "edited_by/editor_of" do
137
- it "finds card edited by joe using subquery" do
138
- @query = { edited_by: { match: "Joe User" } }
139
- is_expected.to include("JoeLater", "JoeNow")
140
- end
141
-
142
- it "finds card edited by Wagn Bot" do
143
- # this is a weak test, since it gives the name, but different sorting
144
- # mechanisms in other db setups
145
- # was having it return *account in some cases and 'A' in others
146
- @query = { edited_by: "Wagn Bot", name: "A" }
147
- is_expected.to eq(%w(A))
148
- end
149
-
150
- it "fails gracefully if user isn't there" do
151
- @query = { edited_by: "Joe LUser" }
152
- is_expected.to eq([])
153
- end
154
-
155
- it "does not give duplicate results for multiple edits" do
156
- c = Card["JoeNow"]
157
- c.content = "testagagin"
158
- c.save
159
- c.content = "test3"
160
- c.save!
161
- @query = { edited_by: "Joe User" }
162
- is_expected.to include("JoeLater", "JoeNow")
163
- end
164
-
165
- it "finds joe user among card's editors" do
166
- @query = { editor_of: "JoeLater" }
167
- is_expected.to eq(["Joe User"])
168
- end
169
- end
170
-
171
- describe "updated_by/updater_of" do
172
- it "finds card updated by Narcissist" do
173
- @query = { updated_by: "Narcissist" }
174
- is_expected.to eq(%w(Magnifier+lens))
175
- end
176
-
177
- it "finds Narcississt as the card's updater" do
178
- @query = { updater_of: "Magnifier+lens" }
179
- is_expected.to eq(%w(Narcissist))
180
- end
181
-
182
- it "does not give duplicate results for multiple updates" do
183
- @query = { updater_of: "First" }
184
- is_expected.to eq(["Wagn Bot"])
185
- end
186
-
187
- it "does not give results if not updated" do
188
- @query = { updater_of: "Sunglasses+price" }
189
- is_expected.to be_empty
190
- end
191
-
192
- it "'or' doesn't mess up updated_by SQL" do
193
- @query = { or: { updated_by: "Narcissist" } }
194
- is_expected.to eq(%w(Magnifier+lens))
195
- end
196
-
197
- it "'or' doesn't mess up updater_of SQL" do
198
- @query = { or: { updater_of: "First" } }
199
- is_expected.to eq(["Wagn Bot"])
200
- end
201
- end
202
-
203
- describe "created_by/creator_of" do
204
- before do
205
- Card.create name: "Create Test", content: "sufficiently distinctive"
206
- end
207
-
208
- it "finds Joe User as the card's creator" do
209
- @query = { creator_of: "Create Test" }
210
- is_expected.to eq(["Joe User"])
211
- end
212
-
213
- it "finds card created by Joe User" do
214
- @query = { created_by: "Joe User", eq: "sufficiently distinctive" }
215
- is_expected.to eq(["Create Test"])
216
- end
217
- end
218
-
219
- describe "last_edited_by/last_editor_of" do
220
- before do
221
- c = Card.fetch("A")
222
- c.content = "peculicious"
223
- c.save!
224
- end
225
-
226
- it "finds Joe User as the card's last editor" do
227
- @query = { last_editor_of: "A" }
228
- is_expected.to eq(["Joe User"])
229
- end
230
-
231
- it "finds card created by Joe User" do
232
- @query = { last_edited_by: "Joe User", eq: "peculicious" }
233
- is_expected.to eq(["A"])
234
- end
235
- end
236
-
237
- describe "keyword" do
238
- it "escapes nonword characters" do
239
- @query = { match: "two :(!" }
240
- is_expected.to eq(CARDS_MATCHING_TWO)
241
- end
242
- end
243
-
244
- describe "search count" do
245
- it "returns integer" do
246
- search = Card.create!(
247
- name: "tmpsearch",
248
- type: "Search",
249
- content: '{"match":"two"}'
250
- )
251
- expect(search.count).to eq(CARDS_MATCHING_TWO.length + 1)
252
- end
253
- end
254
-
255
- describe "vars" do
256
- it "replace placeholders" do
257
- @query = { match: "$keyword", vars: { keyword: "two" } }
258
- is_expected.to eq(CARDS_MATCHING_TWO)
259
- end
260
-
261
- it "replace placeholders in nested queries" do
262
- @query = { and: { match: "$keyword" }, vars: { keyword: "two" } }
263
- is_expected.to eq(CARDS_MATCHING_TWO)
264
- end
265
- end
266
-
267
- describe "content equality" do
268
- it "matchs content explicitly" do
269
- @query = { content: ["=", "I'm number two"] }
270
- is_expected.to eq(["Joe User"])
271
- end
272
-
273
- it "matchs via shortcut" do
274
- @query = { "=" => "I'm number two" }
275
- is_expected.to eq(["Joe User"])
276
- end
277
- end
278
-
279
- describe "links" do
280
- it "handles refer_to" do
281
- @query = { refer_to: "Z" }
282
- is_expected.to eq(%w(A B))
283
- end
284
-
285
- it "handles link_to" do
286
- @query = { link_to: "Z" }
287
- is_expected.to eq(%w(A))
288
- end
289
-
290
- it "handles include" do
291
- @query = { include: "Z" }
292
- is_expected.to eq(%w(B))
293
- end
294
-
295
- it "handles linked_to_by" do
296
- @query = { linked_to_by: "A" }
297
- is_expected.to eq(%w(Z))
298
- end
299
-
300
- it "handles included_by" do
301
- @query = { included_by: "B" }
302
- is_expected.to eq(%w(Z))
303
- end
304
-
305
- it "handles referred_to_by" do
306
- @query = { referred_to_by: "X" }
307
- is_expected.to eq(%w(A A+B T))
308
- end
309
- end
310
-
311
- describe "compound relationships" do
312
- it "right_plus should handle subqueries" do
313
- @query = { right_plus: ["*create", refer_to: "Anyone"] }
314
- is_expected.to eq(["Fruit+*type", "Sign up+*type"])
315
- end
316
-
317
- it "plus should handle subqueries" do # albeit more slowly :)
318
- @query = { plus: ["*create", refer_to: "Anyone"] }
319
- is_expected.to eq(["Fruit+*type", "Sign up+*type"])
320
- end
321
- end
322
-
323
- describe "relative links" do
324
- it "handles relative refer_to" do
325
- @query = { refer_to: "_self", context: "Z" }
326
- is_expected.to eq(%w(A B))
327
- end
328
- end
329
-
330
- describe "permissions" do
331
- it "does not find cards not in group" do
332
- Card::Auth.as_bot do
333
- Card.create name: "C+*self+*read", type: "Pointer", content: "[[R1]]"
334
- end
335
- @query = { plus: "A" }
336
- is_expected.to eq(%w(B D E F))
337
- end
338
- end
339
-
340
- describe "basics" do
341
- it "is case insensitive for name" do
342
- @query = { name: "a" }
343
- is_expected.to eq(["A"])
344
- end
345
-
346
- it "finds plus cards" do
347
- @query = { plus: "A" }
348
- is_expected.to eq(A_JOINEES)
349
- end
350
-
351
- it "finds connection cards" do
352
- @query = { part: "A" }
353
- is_expected.to eq(%w(A+B A+C A+D A+E C+A D+A F+A))
354
- end
355
-
356
- it "finds left connection cards" do
357
- @query = { left: "A" }
358
- is_expected.to eq(%w(A+B A+C A+D A+E))
359
- end
360
-
361
- it "finds right connection cards based on name" do
362
- @query = { right: "A" }
363
- is_expected.to eq(%w(C+A D+A F+A))
364
- end
365
-
366
- it "finds right connection cards based on content" do
367
- @query = { right: { content: "Alpha [[Z]]" } }
368
- is_expected.to eq(%w(C+A D+A F+A))
369
- end
370
-
371
- it "returns count" do
372
- expect(Card.count_by_wql part: "A").to eq(7)
373
- end
374
- end
375
-
376
- describe "limit and offset" do
377
- it "returns limit" do
378
- @query = { part: "A", limit: 5 }
379
- expect(subject.size).to eq(5)
380
- end
381
-
382
- it "does not break if offset but no limit" do
383
- @query = { part: "A", offset: 5 }
384
- expect(subject.size).not_to eq(0)
385
- end
386
-
387
- it "does not break count" do
388
- query = { match: "two", offset: 1 }
389
- expect(Card.count_by_wql(query)).to eq(CARDS_MATCHING_TWO.length)
390
- end
391
- end
392
-
393
- describe "type" do
394
- user_cards = [
395
- "Big Brother", "Joe Admin", "Joe Camel", "Joe User", "John",
396
- "Narcissist", "No Count", "Optic fan", "Sample User", "Sara",
397
- "Sunglasses fan", "u1", "u2", "u3"
398
- ].sort
399
-
400
- it "finds cards of this type" do
401
- @query = { type: "_self", context: "User" }
402
- is_expected.to eq(user_cards)
403
- end
404
-
405
- it "finds User cards " do
406
- @query = { type: "User" }
407
- is_expected.to eq(user_cards)
408
- end
409
-
410
- it "handles casespace variants" do
411
- @query = { type: "users" }
412
- is_expected.to eq(user_cards)
413
- end
414
- end
415
-
416
- describe "trash handling" do
417
- it "does not find cards in the trash" do
418
- Card["A+B"].delete!
419
- @query = { left: "A" }
420
- is_expected.to eq(["A+C", "A+D", "A+E"])
421
- end
422
- end
423
-
424
- describe "match" do
425
- it "reachs content and name via shortcut" do
426
- @query = { match: "two" }
427
- is_expected.to eq(CARDS_MATCHING_TWO)
428
- end
429
-
430
- it "gets only content when content is explicit" do
431
- @query = { content: [:match, "two"] }
432
- is_expected.to eq(["Joe User"])
433
- end
434
-
435
- it "gets only name when name is explicit" do
436
- @query = { name: [:match, "two"] }
437
- is_expected.to eq(["One+Two", "One+Two+Three", "Two"])
438
- end
439
- end
440
-
441
- describe "and" do
442
- it "acts as a simple passthrough with operators" do
443
- @query = { and: { match: "two" } }
444
- is_expected.to eq(CARDS_MATCHING_TWO)
445
- end
446
-
447
- it "acts as a simple passthrough with relationships" do
448
- @query = { and: {}, type: "Cardtype E" }
449
- is_expected.to eq(["type-e-card"])
450
- end
451
-
452
- it 'works within "or"' do
453
- @query = { or: { name: "Z", and: { left: "A", right: "C" } } }
454
- is_expected.to eq(["A+C", "Z"])
455
- end
456
- end
457
-
458
- describe "any" do
459
- it "works with :plus" do
460
- @query = { plus: "A", any: { name: "B", match: "K" } }
461
- is_expected.to eq(["B"])
462
- end
463
-
464
- it "works with multiple plusses" do
465
- @query = { or: { right_plus: "A", plus: "B" } }
466
- is_expected.to eq(%w(A C D F))
467
- end
468
- end
469
-
470
- describe "found_by" do
471
- before do
472
- Card::Auth.as_bot
473
- Card.create(
474
- name: "Simple Search", type: "Search", content: '{"name":"A"}'
475
- )
476
- end
477
-
478
- it "finds cards returned by search of given name" do
479
- @query = { found_by: "Simple Search" }
480
- is_expected.to eq(["A"])
481
- end
482
-
483
- it "finds cards returned by virtual cards" do
484
- image_cards = Card.search type: "Image", return: :name, sort: :name
485
- @query = { found_by: "Image+*type+by name" }
486
- is_expected.to eq(image_cards)
487
- end
488
-
489
- it "plays nicely with other properties and relationships" do
490
- explicit_query = { plus: { name: "A" }, return: :name, sort: :name }
491
- @query = { plus: { found_by: "Simple Search" } }
492
- is_expected.to eq(Card::Query.run(explicit_query))
493
- end
494
-
495
- it "plays work with virtual cards" do
496
- @query = { found_by: "A+*self", plus: "C" }
497
- is_expected.to eq(["A"])
498
- end
499
-
500
- it "is able to handle _self" do
501
- @query = {
502
- context: "Simple Search",
503
- left: { found_by: "_self" },
504
- right: "B",
505
- return: :name
506
- }
507
- is_expected.to eq(["A+B"])
508
- end
509
- end
510
-
511
- describe "relative" do
512
- it "cleans wql" do
513
- query = Card::Query.new(part: "_self", context: "A")
514
- expect(query.statement[:part]).to eq("A")
515
- end
516
-
517
- it "finds connection cards" do
518
- @query = { part: "_self", context: "A" }
519
- is_expected.to eq(%w(A+B A+C A+D A+E C+A D+A F+A))
520
- end
521
-
522
- it "is able to use parts of nonexistent cards in search" do
523
- expect(Card["B+A"]).to be_nil
524
- @query = { left: "_right", right: "_left", context: "B+A" }
525
- is_expected.to eq(["A+B"])
526
- end
527
-
528
- it "finds plus cards for _self" do
529
- @query = { plus: "_self", context: "A" }
530
- is_expected.to eq(A_JOINEES)
531
- end
532
-
533
- it "finds plus cards for _left" do
534
- @query = { plus: "_left", context: "A+B" }
535
- is_expected.to eq(A_JOINEES)
536
- end
537
-
538
- it "finds plus cards for _right" do
539
- @query = { plus: "_right", context: "C+A" }
540
- is_expected.to eq(A_JOINEES)
541
- end
542
- end
543
-
544
- describe "nested permissions" do
545
- it "are generated by default" do
546
- perm_count = 0
547
- sql = Card::Query.new(left: { name: "X" }).sql
548
- sql.scan(/read_rule_id IN \([\d\,]+\)/) do
549
- perm_count += 1
550
- end
551
- expect(perm_count).to eq(2)
552
- end
553
- end
554
-
555
- describe "return part of name" do
556
- subject do
557
- Card::Query.run right: "C", return: @return, sort: :name
558
- end
559
- it "handles _left" do
560
- @return = "_left"
561
- is_expected.to eq %w(A+B A)
562
- end
563
-
564
- it "handles _right" do
565
- @return = "_right"
566
- is_expected.to eq %w(C C)
567
- end
568
-
569
- it "handles _LL" do
570
- @return = "_LL"
571
- is_expected.to eq ["A", "A+C"]
572
- end
573
- end
574
- end