was 0.7.0 → 0.8.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 32828b1a84ec32fd591c751dcb5df91f277af4d6bc840179b9070345f3345e24
4
- data.tar.gz: 57bfb59c5ee299e3e0ed0376e44b4ad0c62f98ca23574cf366fc5f7461a1dd95
3
+ metadata.gz: 974fa97c47b4fe794512983c75fa065b9bdd40370e5987b1e4523d01791bdd2a
4
+ data.tar.gz: 9f6e783dd2fbad215e8c2b16c820a1b8642b843efba424ed2d35e5aa1e7e2b92
5
5
  SHA512:
6
- metadata.gz: e006ec3f57273eafe64336a6ba55efc358bed7064a11be9ff67089a147b3683e8452c447d09caf59f306a573265ab52bc4f1fd411f25e5020b3773a55355df4d
7
- data.tar.gz: 24f01eb4452fa8b691bbcf1c639cd16ae72d53f10920f2482281ef853ce0b0f9b792aea36c3a7498a2caf22f2ced4aecc3fa5f0e8bf46d9ee2d387c4234cbfeb
6
+ metadata.gz: 43d1c61377ad1da1477d5edf911fd55b22acea765ffcf10e53c3cdc2c181e7968bd3bc02223721a82146c57b5186f79d25b75557026cedecb30dfc218a56e801
7
+ data.tar.gz: 6c09a8018b3d7fb5634985e3144d75adc942a21b3b6b459057192b1f0918bfee840b54a8897dc9ad25983623cbdf858b40c9e72f84ab073d3a891592998e5d41
data/README.md CHANGED
@@ -14,8 +14,14 @@ Scenario:
14
14
  * 'C' is 50%
15
15
  * 'D' is 0%
16
16
  * The practical is a simple mark out of 10.
17
- * 4 out of 10 is 40%
18
- * The person is given a final score out of 1000.
17
+ * 4 out of 10 is 40%
18
+ * The person is given a final score out of 1000.
19
+
20
+ ### Install the RubyGem
21
+
22
+ ```bash
23
+ gem install was
24
+ ```
19
25
 
20
26
  ### Define score classes
21
27
 
@@ -25,8 +31,8 @@ require "was"
25
31
  class ReportScore < WAS::Score
26
32
  maximum_score 1000
27
33
 
28
- with :exam, class_name: "ExamScore", weight: 0.75
29
- with :practical class_name: "PracticalScore", weight: 0.25
34
+ with :exam, class_name: "ExamScore", weight: 0.75
35
+ with :practical, class_name: "PracticalScore", weight: 0.25
30
36
  end
31
37
 
32
38
  class ExamScore < WAS::Score
@@ -77,8 +83,8 @@ Omitting the `maximum_score` will return a composed percentage represented as a
77
83
  ```ruby
78
84
  # report_score.rb
79
85
  class ReportScore < WAS::Score
80
- with :exam, class_name: "ExamScore", weight: 0.75
81
- with :practical class_name: "PracticalScore", weight: 0.25
86
+ with :exam, class_name: "ExamScore", weight: 0.75
87
+ with :practical, class_name: "PracticalScore", weight: 0.25
82
88
  end
83
89
  ```
84
90
 
@@ -91,9 +97,80 @@ ReportScore.new({
91
97
  #> 0.875
92
98
  ```
93
99
 
100
+ ### Working with a score tree
101
+
102
+ For more complex scenarios, we might need to know more about how the score was composed.
103
+
104
+ Using the example `ReportScore`, `ExamScore`, and `PracticalScore` classes as
105
+ an example, we can generate a tree of scores:
106
+
107
+ ```ruby
108
+ tree = ReportScore.new({
109
+ exam: "A",
110
+ practical: 5
111
+ }).calculate(:tree)
112
+
113
+ #> tree
114
+ {
115
+ score: 875.0,
116
+ max: 1000,
117
+ deduction: -125.0,
118
+ with: {
119
+ exam: {
120
+ score: 750.0,
121
+ max: 750.0,
122
+ deduction: 0.0,
123
+ weight: 0.75
124
+ },
125
+ practical: {
126
+ score: 125.0,
127
+ max: 250.0,
128
+ deduction: -125.0,
129
+ weight: 0.25
130
+ }
131
+ }
132
+ }
133
+ ```
134
+
135
+ This result is a `WAS::Tree` object. Basically a `Hash` with some extra
136
+ added to it.
137
+
138
+ #### Ordering by attribute
139
+
140
+ For each of the key attributes `:score`, `:max`, `:weight`, and
141
+ `:deduction`, we can order our tree interally by that key:
142
+
143
+ ```ruby
144
+ #> tree.order(:deduction)
145
+ {
146
+ score: 875.0,
147
+ max: 1000,
148
+ deduction: -125.0
149
+ with: {
150
+ practical: {
151
+ score: 125.0,
152
+ max: 250.0,
153
+ deduction: -125.0,
154
+ weight: 0.25
155
+ },
156
+ exam: {
157
+ score: 750.0,
158
+ max: 750.0,
159
+ deduction: 0.0,
160
+ weight: 0.75
161
+ }
162
+ }
163
+ }
164
+ ```
165
+
166
+ For `:deduction`, results adjacent to each other are ordered by the
167
+ _most negative_. For all other options, the values are ordered largest
168
+ value first.
169
+
94
170
  ### View all weights
95
171
 
96
- If you want to see all of the weights that are used to compose the score, there is a convenience method `.weights`:
172
+ If you want to see all of the weights that are used to compose the score,
173
+ there is a convenience method `.weights`:
97
174
 
98
175
  ```ruby
99
176
  ReportScore.weights
data/lib/was/score.rb CHANGED
@@ -45,9 +45,12 @@ module WAS
45
45
 
46
46
  calc = calculation(:tree)
47
47
  tree = if calc.is_a?(Hash)
48
- calc.merge({ max: self.class.max_score })
48
+ calc.merge(additional_score_attributes(calc[:score]))
49
49
  else
50
- { score: calc }.merge({ max: self.class.max_score })
50
+ {}.tap do |t|
51
+ t.merge!(score: calc)
52
+ t.merge!(additional_score_attributes(calc))
53
+ end
51
54
  end
52
55
 
53
56
  transform_scores_relative_to_max_score(tree)
@@ -63,6 +66,13 @@ module WAS
63
66
 
64
67
  private
65
68
 
69
+ def additional_score_attributes(score_value)
70
+ {
71
+ max: self.class.max_score,
72
+ deduction: (score_value - self.class.max_score).round(8)
73
+ }
74
+ end
75
+
66
76
  def transform_scores_relative_to_max_score(tree, max_score = nil)
67
77
  max_score = max_score || self.class.max_score
68
78
  return tree if self.class.max_score == 1
@@ -71,7 +81,7 @@ module WAS
71
81
  next if key != :with
72
82
 
73
83
  value.each do |scorer, branch|
74
- adjust_branch_score_and_max(branch, max_score)
84
+ adjust_values_relative_to_max_score(branch, max_score)
75
85
  end
76
86
 
77
87
  value.transform_values! do |nested_tree|
@@ -80,9 +90,10 @@ module WAS
80
90
  end
81
91
  end
82
92
 
83
- def adjust_branch_score_and_max(branch, max_score)
84
- branch[:max] = branch[:max] * max_score * branch[:weight]
93
+ def adjust_values_relative_to_max_score(branch, max_score)
94
+ branch[:max] = branch[:max] * max_score * branch[:weight]
85
95
  branch[:score] = branch[:score] * branch[:max]
96
+ branch[:deduction] = branch[:score] - branch[:max]
86
97
  end
87
98
 
88
99
  def contexts?
@@ -99,7 +110,10 @@ module WAS
99
110
 
100
111
  def nested_score_calcuation(option)
101
112
  if option == :tree
102
- { score: sum, with: with_attribute }
113
+ WAS::Tree.new.tap do |t|
114
+ t[:score] = sum
115
+ t[:with] = with_attribute
116
+ end
103
117
  else
104
118
  sum
105
119
  end
data/lib/was/tree.rb ADDED
@@ -0,0 +1,31 @@
1
+ module WAS
2
+ class Tree < Hash
3
+ def order(order_key = :deduction)
4
+ self.dup.tap do |tree|
5
+ return tree if tree[:with].nil?
6
+
7
+ sort_with_by!(order_key, tree)
8
+ end
9
+ end
10
+
11
+ private
12
+
13
+ def sort_with_by!(order_key, tree)
14
+ return tree if tree[:with].nil?
15
+
16
+ tree[:with].each do |_, subtree|
17
+ sort_with_by!(order_key, subtree)
18
+ end
19
+
20
+ array = tree[:with].sort_by do |_, subtree|
21
+ subtree[order_key]
22
+ end
23
+
24
+ tree[:with] = if order_key == :deduction
25
+ array.to_h
26
+ else
27
+ array.reverse.to_h
28
+ end
29
+ end
30
+ end
31
+ end
data/lib/was/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module WAS
4
- VERSION = "0.7.0"
4
+ VERSION = "0.8.0"
5
5
  end
data/lib/was.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "was/version"
4
+ require_relative "was/tree"
4
5
  require_relative "was/score"
5
6
 
6
7
  module WAS
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: was
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mark Connell
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-02-20 00:00:00.000000000 Z
11
+ date: 2025-02-26 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A simple gem/dsl for generating Weighted Average Score calculations.
14
14
  email:
@@ -23,6 +23,7 @@ files:
23
23
  - Rakefile
24
24
  - lib/was.rb
25
25
  - lib/was/score.rb
26
+ - lib/was/tree.rb
26
27
  - lib/was/version.rb
27
28
  - sig/was.rbs
28
29
  - was.gemspec