barker 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/.simplecov +7 -0
  6. data/Gemfile +6 -0
  7. data/Gemfile.lock +50 -0
  8. data/LICENSE +22 -0
  9. data/README.md +204 -0
  10. data/Rakefile +12 -0
  11. data/barker.gemspec +29 -0
  12. data/ci/run +20 -0
  13. data/lib/barker/answer.rb +11 -0
  14. data/lib/barker/api/base.rb +145 -0
  15. data/lib/barker/api/response/base.rb +25 -0
  16. data/lib/barker/api/response/candidate.rb +38 -0
  17. data/lib/barker/api/response/candidate_answer.rb +23 -0
  18. data/lib/barker/api/response/candidate_joker.rb +21 -0
  19. data/lib/barker/api/response/candidate_question.rb +51 -0
  20. data/lib/barker/api/response/error.rb +17 -0
  21. data/lib/barker/api/response/game_show.rb +43 -0
  22. data/lib/barker/api/response/round.rb +21 -0
  23. data/lib/barker/api/response.rb +15 -0
  24. data/lib/barker/api.rb +7 -0
  25. data/lib/barker/candidate.rb +52 -0
  26. data/lib/barker/candidate_answer.rb +42 -0
  27. data/lib/barker/candidate_joker.rb +30 -0
  28. data/lib/barker/candidate_question.rb +116 -0
  29. data/lib/barker/candidate_round.rb +32 -0
  30. data/lib/barker/entity.rb +15 -0
  31. data/lib/barker/game_show.rb +176 -0
  32. data/lib/barker/guideline/base.rb +33 -0
  33. data/lib/barker/guideline/llmcquiz/questions.yaml +300 -0
  34. data/lib/barker/guideline/llmcquiz.rb +28 -0
  35. data/lib/barker/guideline/mock.rb +17 -0
  36. data/lib/barker/guideline.rb +8 -0
  37. data/lib/barker/import/yaml.rb +22 -0
  38. data/lib/barker/import.rb +6 -0
  39. data/lib/barker/joker.rb +28 -0
  40. data/lib/barker/question.rb +12 -0
  41. data/lib/barker/quiz.rb +19 -0
  42. data/lib/barker/repo/memory/game_show.rb +38 -0
  43. data/lib/barker/repo/memory.rb +8 -0
  44. data/lib/barker/repo.rb +6 -0
  45. data/lib/barker/round.rb +68 -0
  46. data/lib/barker/stage.rb +38 -0
  47. data/lib/barker/store/memory.rb +158 -0
  48. data/lib/barker/store.rb +6 -0
  49. data/lib/barker/validations.rb +14 -0
  50. data/lib/barker/version.rb +3 -0
  51. data/lib/barker.rb +45 -0
  52. data/test/factories/answer.rb +21 -0
  53. data/test/factories/candidate.rb +23 -0
  54. data/test/factories/candidate_answer.rb +12 -0
  55. data/test/factories/candidate_joker.rb +8 -0
  56. data/test/factories/candidate_question.rb +16 -0
  57. data/test/factories/candidate_round.rb +8 -0
  58. data/test/factories/game_show.rb +12 -0
  59. data/test/factories/joker.rb +5 -0
  60. data/test/factories/question.rb +13 -0
  61. data/test/factories/quiz.rb +11 -0
  62. data/test/factories/round.rb +12 -0
  63. data/test/factories/stage.rb +12 -0
  64. data/test/fixtures/questions.yaml +20 -0
  65. data/test/test_helper.rb +72 -0
  66. data/test/test_mocks.rb +21 -0
  67. data/test/unit/answer_test.rb +49 -0
  68. data/test/unit/api/base_test.rb +207 -0
  69. data/test/unit/api/response/base_test.rb +35 -0
  70. data/test/unit/api/response/candidate_answer_test.rb +64 -0
  71. data/test/unit/api/response/candidate_joker_test.rb +60 -0
  72. data/test/unit/api/response/candidate_question_test.rb +99 -0
  73. data/test/unit/api/response/candidate_test.rb +82 -0
  74. data/test/unit/api/response/game_show_test.rb +105 -0
  75. data/test/unit/api/response/round_test.rb +49 -0
  76. data/test/unit/candidate_answer_test.rb +66 -0
  77. data/test/unit/candidate_question_test.rb +277 -0
  78. data/test/unit/candidate_round_test.rb +64 -0
  79. data/test/unit/candidate_test.rb +76 -0
  80. data/test/unit/game_show_test.rb +372 -0
  81. data/test/unit/guideline/base_test.rb +34 -0
  82. data/test/unit/guideline/llmcquiz_test.rb +35 -0
  83. data/test/unit/guideline/mock_test.rb +33 -0
  84. data/test/unit/import/yaml_test.rb +41 -0
  85. data/test/unit/joker_test.rb +32 -0
  86. data/test/unit/question_test.rb +55 -0
  87. data/test/unit/quiz_test.rb +37 -0
  88. data/test/unit/repo/memory/game_show_test.rb +54 -0
  89. data/test/unit/round_test.rb +167 -0
  90. data/test/unit/stage_test.rb +53 -0
  91. metadata +283 -0
@@ -0,0 +1,158 @@
1
+ require 'thread_safe'
2
+
3
+ module Barker
4
+ module Store
5
+ class Memory
6
+ def initialize(key, options = {})
7
+ @key = key
8
+ @index = ThreadSafe::Cache.new
9
+ @build_key = options[:build_key] || false
10
+ init_index options[:init]
11
+ end
12
+
13
+ def add(item)
14
+ key = lookup_key(item)
15
+
16
+ raise DuplicateError if exist?(key)
17
+
18
+ __add(key, item)
19
+ item
20
+ end
21
+
22
+ def update(item)
23
+ key = key(item)
24
+ raise NotFoundError unless exist?(key)
25
+ @index[key] = deep_copy(item)
26
+ end
27
+
28
+ def remove(item)
29
+ key = key(item)
30
+ raise NotFoundError unless exist?(key)
31
+ @index.delete(key)
32
+ end
33
+
34
+ def filter(&block)
35
+ @index.values.select(&block)
36
+ end
37
+
38
+ def exist?(key)
39
+ @index.key?(key)
40
+ end
41
+
42
+ def get(key)
43
+ if item = __get(key)
44
+ deep_copy(item)
45
+ end
46
+ end
47
+
48
+ def select(group_by, *values)
49
+ conditions = Hash[Array(group_by).each_with_index.map do |group, i|
50
+ [group, values[i]]
51
+ end]
52
+
53
+ __all.select do |item|
54
+ conditions.each.all? do |k, v|
55
+ item.respond_to?(k) && item.public_send(k) == v
56
+ end
57
+ end
58
+ end
59
+
60
+ def all
61
+ deep_copy(__all)
62
+ end
63
+
64
+ def size
65
+ @index.size
66
+ end
67
+
68
+ def reload(item)
69
+ if item
70
+ get(key(item))
71
+ else
72
+ nil
73
+ end
74
+ end
75
+
76
+ def update_attributes(key, attributes)
77
+ if item = __get(key)
78
+ attributes.each do |attribute, value|
79
+ item.public_send("#{attribute}=", value)
80
+ end
81
+ end
82
+
83
+ get(key)
84
+ end
85
+
86
+ private
87
+
88
+ def key(item)
89
+ item.send(@key)
90
+ end
91
+
92
+ def deep_copy(object)
93
+ Marshal.load(Marshal.dump(object))
94
+ end
95
+
96
+ def __get(key)
97
+ @index[key]
98
+ end
99
+
100
+ def __add(key, item)
101
+ copy = deep_copy(item)
102
+ add_to_index key, copy
103
+ end
104
+
105
+ def __all
106
+ @index.values
107
+ end
108
+
109
+ def each_group(&block)
110
+ @group_by.each(&block)
111
+ end
112
+
113
+ def add_to_index(key, item)
114
+ @index[key] = item
115
+ end
116
+
117
+ def build_key?
118
+ @build_key
119
+ end
120
+
121
+ def lookup_key(item)
122
+ if build_key?
123
+ assign_generated_key(item)
124
+ else
125
+ key(item)
126
+ end
127
+ end
128
+
129
+ def assign_generated_key(item)
130
+ raise KeyPresetError if key(item)
131
+ key = next_key!
132
+ item.send("#{@key}=", key)
133
+ key
134
+ end
135
+
136
+ def next_key!
137
+ @current_key ||= 0
138
+ (@current_key += 1).to_s
139
+ end
140
+
141
+ def init_index(items = nil)
142
+ if items
143
+ unless build_key?
144
+ keys = Hash.new {|h,k| h[k] = 0}
145
+ items.each do |item|
146
+ keys[key(item)] += 1
147
+ end
148
+ raise DuplicateError if keys.values.any?{|v| v > 1}
149
+ end
150
+
151
+ items.each do |item|
152
+ __add(lookup_key(item), item)
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,6 @@
1
+ require 'barker/store/memory'
2
+
3
+ module Barker
4
+ module Store
5
+ end
6
+ end
@@ -0,0 +1,14 @@
1
+ module Barker
2
+ module Validations
3
+ module NumericalityOfId
4
+ def self.included(base)
5
+ base.validate :numericality_of_id
6
+ end
7
+
8
+ def numericality_of_id
9
+ self.class.validates :id, :numericality => { :only_integer => true }
10
+ errors.add(:id, 'is not a number') if id.kind_of? String
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ module Barker
2
+ VERSION = "0.2.2"
3
+ end
data/lib/barker.rb ADDED
@@ -0,0 +1,45 @@
1
+ module Barker
2
+ module Errors
3
+ BarkerError = Class.new(RuntimeError)
4
+
5
+ AlreadyAnsweredError = Class.new(BarkerError)
6
+ AnswerNotFoundError = Class.new(BarkerError)
7
+ JokerAlreadyUsedError = Class.new(BarkerError)
8
+ HasToRespondToIdError = Class.new(BarkerError)
9
+ HasToRespondToLocaleError = Class.new(BarkerError)
10
+ UnknownJokerError = Class.new(BarkerError)
11
+ NoCurrentStageError = Class.new(BarkerError)
12
+ NotStartedError = Class.new(BarkerError)
13
+ AlreadyStartedError = Class.new(BarkerError)
14
+ FileNotExistError = Class.new(BarkerError)
15
+ RecordNotFound = Class.new(BarkerError)
16
+ end
17
+ end
18
+
19
+ require 'forwardable'
20
+ require 'active_support/all'
21
+ require 'active_model'
22
+
23
+ require "barker/version"
24
+ require "barker/validations"
25
+
26
+ require "barker/store"
27
+ require "barker/repo"
28
+ require "barker/api"
29
+ require "barker/guideline"
30
+ require "barker/import"
31
+
32
+ require "barker/game_show"
33
+ require "barker/entity"
34
+ require "barker/answer"
35
+ require "barker/question"
36
+ require "barker/quiz"
37
+ require "barker/stage"
38
+ require "barker/round"
39
+ require "barker/joker"
40
+ require "barker/candidate"
41
+
42
+ require "barker/candidate_answer"
43
+ require "barker/candidate_question"
44
+ require "barker/candidate_round"
45
+ require "barker/candidate_joker"
@@ -0,0 +1,21 @@
1
+ FactoryGirl.define do
2
+ factory :answer, :class => Barker::Answer do
3
+ sequence(:id) { |i| i }
4
+ sequence(:label) {{ "en" => "answer", "de" => "antwort" }}
5
+ sequence(:correct) { |i| i.odd? }
6
+
7
+ trait :correct do
8
+ correct true
9
+ end
10
+
11
+ trait :wrong do
12
+ correct false
13
+ end
14
+
15
+ trait :invalid do
16
+ id "not_a_number"
17
+ end
18
+
19
+ initialize_with { new(id, label, correct) }
20
+ end
21
+ end
@@ -0,0 +1,23 @@
1
+ require 'test_mocks'
2
+
3
+ FactoryGirl.define do
4
+ factory :candidate, :class => Barker::Candidate do
5
+ sequence(:object) {|i| Mock::ValidUser.new(:id => i)}
6
+ initialize_with { new(object) }
7
+ end
8
+
9
+ factory :valid_candidate, :class => Barker::Candidate do
10
+ sequence(:object) {|i| Mock::ValidUser.new(:id => i)}
11
+ initialize_with { new(object) }
12
+ end
13
+
14
+ factory :candidate_without_id, :class => Barker::Candidate do
15
+ object { Mock::UserWithoutId.new }
16
+ initialize_with { new(object) }
17
+ end
18
+
19
+ factory :candidate_without_locale, :class => Barker::Candidate do
20
+ object { Mock::UserWithoutLocale.new }
21
+ initialize_with { new(object) }
22
+ end
23
+ end
@@ -0,0 +1,12 @@
1
+ FactoryGirl.define do
2
+ factory :candidate_answer, :class => Barker::CandidateAnswer do
3
+ candidate { FactoryGirl.build(:candidate) }
4
+ answer { FactoryGirl.build(:answer) }
5
+
6
+ trait :invalid do
7
+ answer { FactoryGirl.build(:answer, :invalid) }
8
+ end
9
+
10
+ initialize_with { new(candidate, answer) }
11
+ end
12
+ end
@@ -0,0 +1,8 @@
1
+ FactoryGirl.define do
2
+ factory :candidate_joker, :class => Barker::CandidateJoker do
3
+ candidate { FactoryGirl.build(:candidate) }
4
+ joker { FactoryGirl.build(:joker) }
5
+
6
+ initialize_with { new(candidate, joker) }
7
+ end
8
+ end
@@ -0,0 +1,16 @@
1
+ FactoryGirl.define do
2
+ factory :candidate_question, :class => Barker::CandidateQuestion do
3
+ candidate { FactoryGirl.build(:candidate) }
4
+ question { FactoryGirl.build(:question) }
5
+
6
+ trait :valid do
7
+ asked_at { Time.now }
8
+ answered_at { Time.now + 1 }
9
+ end
10
+
11
+ trait :invalid do
12
+ end
13
+
14
+ initialize_with { new(candidate, question) }
15
+ end
16
+ end
@@ -0,0 +1,8 @@
1
+ FactoryGirl.define do
2
+ factory :candidate_round, :class => Barker::CandidateRound do
3
+ round { FactoryGirl.build(:round) }
4
+ candidate { round.candidates[0] }
5
+
6
+ initialize_with { new(candidate, round) }
7
+ end
8
+ end
@@ -0,0 +1,12 @@
1
+ FactoryGirl.define do
2
+ factory :game_show, :class => Barker::GameShow do
3
+ candidates { FactoryGirl.build_list(:candidate, 2) }
4
+ quizzes { FactoryGirl.build_list(:quiz, 2) }
5
+
6
+ trait :invalid do
7
+ candidates { [] }
8
+ end
9
+
10
+ initialize_with { new(quizzes, candidates) }
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ FactoryGirl.define do
2
+ factory :joker, :class => Barker::Joker do
3
+ initialize_with { new("fifty_fifty") }
4
+ end
5
+ end
@@ -0,0 +1,13 @@
1
+ FactoryGirl.define do
2
+ factory :question, :class => Barker::Question do
3
+ sequence(:id) { |i| i }
4
+ label {{ "en" => "question", "de" => "frage" }}
5
+ answers { FactoryGirl.build_list(:answer, 2) }
6
+
7
+ trait :invalid do
8
+ id "not_a_number"
9
+ end
10
+
11
+ initialize_with { new(id, label, answers) }
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ FactoryGirl.define do
2
+ factory :quiz, :class => Barker::Quiz do
3
+ questions { FactoryGirl.build_list(:question, 2) }
4
+
5
+ trait :invalid do
6
+ questions { [FactoryGirl.build(:question),FactoryGirl.build(:question, :invalid)] }
7
+ end
8
+
9
+ initialize_with { new(questions) }
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ FactoryGirl.define do
2
+ factory :round, :class => Barker::Round do
3
+ question { FactoryGirl.build(:question) }
4
+ candidates { FactoryGirl.build_list(:candidate, 2) }
5
+
6
+ trait :invalid do
7
+ question { FactoryGirl.build(:question, :invalid) }
8
+ end
9
+
10
+ initialize_with { new(question, candidates) }
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ FactoryGirl.define do
2
+ factory :stage, :class => Barker::Stage do
3
+ quiz { FactoryGirl.build(:quiz) }
4
+ candidates { FactoryGirl.build_list(:candidate, 2) }
5
+
6
+ trait :invalid do
7
+ quiz { FactoryGirl.build(:quiz, :invalid) }
8
+ end
9
+
10
+ initialize_with { new(quiz, candidates) }
11
+ end
12
+ end
@@ -0,0 +1,20 @@
1
+ 1:
2
+ label:
3
+ de: Wann ist der SuperCode nach Kauf einlösbar?
4
+ answers:
5
+ 1:
6
+ correct: false
7
+ label:
8
+ de: 10 Minuten
9
+ 2:
10
+ correct: true
11
+ label:
12
+ de: 30 Minuten
13
+ 3:
14
+ correct: false
15
+ label:
16
+ de: 5 Minuten
17
+ 4:
18
+ correct: false
19
+ label:
20
+ de: sofort
@@ -0,0 +1,72 @@
1
+ require 'bundler/setup'
2
+ require 'simplecov' if ENV['COVERAGE']
3
+ require 'minitest/autorun'
4
+ require 'barker'
5
+ require 'factory_girl'
6
+ require 'mocha/setup'
7
+ require 'test_mocks'
8
+
9
+ class Spec < MiniTest::Spec
10
+ FactoryGirl.find_definitions
11
+
12
+ class << self
13
+ alias :context :describe
14
+ alias :test :it
15
+ end
16
+
17
+ # time
18
+ let(:time) { Time.parse('20:00') }
19
+ let(:started_at) { time }
20
+ let(:asked_at) { started_at + 2.seconds }
21
+ let(:finished_at) { started_at + 120.seconds }
22
+ let(:answered_at) { asked_at + 20.seconds }
23
+ let(:delay) { answered_at - asked_at }
24
+
25
+ # candidate
26
+ let(:candidates) { [FactoryGirl.build(:candidate)] }
27
+ let(:candidate) { candidates.first }
28
+ let(:candidate_without_id) { FactoryGirl.build(:candidate_without_id) }
29
+ let(:candidate_without_locale) { FactoryGirl.build(:candidate_without_locale) }
30
+
31
+ # answer
32
+ let(:answers) { [correct_answer, wrong_answer] }
33
+ let(:answer) { answers.first }
34
+ let(:correct_answer) { FactoryGirl.build(:answer, :correct, :id => 1) }
35
+ let(:wrong_answer) { FactoryGirl.build(:answer, :wrong, :id => 2) }
36
+ let(:candidate_answer) { Barker::CandidateAnswer.new(candidate, answer) }
37
+
38
+ # question
39
+ let(:questions) { FactoryGirl.build_list(:question, 2, :answers => answers) }
40
+ let(:question) { questions.first }
41
+ let(:candidate_question) { Barker::CandidateQuestion.new(candidate, question) }
42
+
43
+ # quiz
44
+ let(:quiz) { Barker::Quiz.new(questions) }
45
+
46
+ # quizshow
47
+ let(:quizshow) { Barker::Quizshow.create(quiz, candidates) }
48
+
49
+ def fake_ctime(file, time)
50
+ $ctime_fake_hash = {
51
+ file => time
52
+ }
53
+ File.class_eval do
54
+ class << self
55
+ alias :old_ctime :ctime
56
+
57
+ def ctime(filepath)
58
+ $ctime_fake_hash[filepath] || old_ctime(filepath)
59
+ end
60
+ end
61
+ end
62
+
63
+ yield
64
+ ensure
65
+ File.class_eval do
66
+ class << self
67
+ alias :ctime :old_ctime
68
+ end
69
+ end
70
+ end
71
+
72
+ end
@@ -0,0 +1,21 @@
1
+ module Mock
2
+ class ValidUser
3
+ attr_reader :id
4
+
5
+ def initialize(options = {})
6
+ @id = options.delete(:id) || rand(Time.now.to_i)
7
+ end
8
+
9
+ def locale
10
+ :en
11
+ end
12
+ end
13
+
14
+ class UserWithoutId < ValidUser
15
+ undef :id
16
+ end
17
+
18
+ class UserWithoutLocale < ValidUser
19
+ undef :locale
20
+ end
21
+ end
@@ -0,0 +1,49 @@
1
+ require 'test_helper'
2
+
3
+ module Barker
4
+ class AnswerTest < Spec
5
+
6
+ test "interface" do
7
+ Barker::Answer.new(1, {"en" => "label"}, true)
8
+ end
9
+
10
+ test "valid factory" do
11
+ assert FactoryGirl.build(:answer).valid?
12
+ end
13
+
14
+ test "invalid factory" do
15
+ refute FactoryGirl.build(:answer, :invalid).valid?
16
+ end
17
+
18
+ test "validate numerically of id" do
19
+ assert FactoryGirl.build(:answer, :id => 1).valid?
20
+ refute FactoryGirl.build(:answer, :id => 1.5).valid?
21
+ refute FactoryGirl.build(:answer, :id => "1").valid?
22
+ end
23
+
24
+ test "equality by id" do
25
+ assert_equal FactoryGirl.build(:answer, :id => 1), FactoryGirl.build(:answer, :id => 1)
26
+ refute_equal FactoryGirl.build(:answer, :id => 1), FactoryGirl.build(:answer, :id => 2)
27
+ end
28
+
29
+ test "id" do
30
+ assert_equal 1, FactoryGirl.build(:answer, :id => 1).id
31
+ end
32
+
33
+ test "label" do
34
+ label = { "en" => "answer", "de" => "antwort" }
35
+ assert_equal label, FactoryGirl.build(:answer, :label => label).label
36
+ end
37
+
38
+ test "correct?" do
39
+ assert correct.correct?
40
+ refute wrong.correct?
41
+ end
42
+
43
+ private
44
+
45
+ let(:correct) { FactoryGirl.build(:answer, :correct) }
46
+ let(:wrong) { FactoryGirl.build(:answer, :wrong) }
47
+
48
+ end
49
+ end