job_dollars 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 93c5f216180ff72d2df380c54fe76c74c39514cb
4
+ data.tar.gz: 2f2ca2f47c34ba02c58eba37959285ef8b8e92c0
5
+ SHA512:
6
+ metadata.gz: 9945ef0043844f89ec810a371e4e746723259656746487d37bf78ce9dcd0d0aacf67630f6c5d30b5bd3e9f653c2297cb897ff6d5fb67085aacb41da4143bcf8e
7
+ data.tar.gz: 40662a9fa558a8aae8907f9986e55cc46c37d6a522e32985a751d70480792ff56aef7283f17265cc0dfb605b7193d042a8848b173b5e77ec7ed7ae8d0437654c
@@ -0,0 +1,30 @@
1
+ require File.join(File.dirname(__FILE__), './job_dollars/core_ext/hash.rb')
2
+ require File.join(File.dirname(__FILE__), './job_dollars/core_ext/hash_with_indifferent_access.rb')
3
+ require File.join(File.dirname(__FILE__), './job_dollars/estimator.rb')
4
+
5
+ require 'yaml'
6
+
7
+ # JobDollars is the main module to include to start using JobDollars. It automatically
8
+ # includes the built-in Estimator module, along with some constants.
9
+ #
10
+ # Example (IRB):
11
+ #
12
+ # irb(main):001:0> require 'job_dollars'
13
+ # => true
14
+ # irb(main):002:0> include JobDollars
15
+ # => Object
16
+ # irb(main):006:0> beginner_javagrad_rating(JOB_DATA['java-android'])
17
+ # => 17.541885876163494
18
+ module JobDollars
19
+ DATA_YML_FILE = File.join(File.dirname(__FILE__), './job_dollars.yml')
20
+
21
+ extend Estimator
22
+
23
+ def self.included(base)
24
+ base.include Estimator
25
+ end
26
+
27
+ JOB_DATA = YAML.load(File.read(DATA_YML_FILE))
28
+ JAVAGRAD_IN_JOB_DOLLARS = market_work_in_job_dollars(0.0, JOB_DATA["java-swing"])
29
+ end
30
+
@@ -0,0 +1,329 @@
1
+ --- !map:HashWithIndifferentAccess
2
+
3
+ csharp-dotnet:
4
+ salaries:
5
+ entry: >
6
+ $65,000+ (2686)
7
+ $75,000+ (2243)
8
+ $80,000+ (1913)
9
+ $90,000+ (1218)
10
+ $100,000+ (637)
11
+
12
+ mid: >
13
+ $85,000+ (1823)
14
+ $95,000+ (1544)
15
+ $105,000+ (1122)
16
+ $110,000+ (906)
17
+ $120,000+ (477)
18
+
19
+ senior: >
20
+ $100,000+ (610)
21
+ $110,000+ (482)
22
+ $115,000+ (363)
23
+ $120,000+ (280)
24
+ $130,000+ (142)
25
+
26
+ jobs:
27
+ entry: 3137
28
+ mid: 11974
29
+ senior: 3422
30
+
31
+ resumes: 128_839
32
+
33
+ ruby-rails:
34
+ salaries:
35
+ entry: >
36
+ $75,000+ (777)
37
+ $90,000+ (634)
38
+ $100,000+ (500)
39
+ $105,000+ (383)
40
+ $115,000+ (198)
41
+
42
+ mid: >
43
+ $85,000+ (1823)
44
+ $95,000+ (1544)
45
+ $105,000+ (1122)
46
+ $110,000+ (906)
47
+ $120,000+ (477)
48
+
49
+ senior: >
50
+ $100,000+ (610)
51
+ $110,000+ (482)
52
+ $115,000+ (363)
53
+ $120,000+ (280)
54
+ $130,000+ (142)
55
+
56
+ jobs:
57
+ entry: 908
58
+ mid: 2088
59
+ senior: 718
60
+
61
+ resumes: 20_269
62
+
63
+ javascript-redux:
64
+ salaries:
65
+ entry: >
66
+ $80,000+ (64)
67
+ $95,000+ (48)
68
+ $100,000+ (38)
69
+ $105,000+ (27)
70
+ $110,000+ (21)
71
+
72
+ mid: >
73
+ $90,000+ (127)
74
+ $100,000+ (106)
75
+ $105,000+ (83)
76
+ $110,000+ (64)
77
+ $120,000+ (29)
78
+
79
+ senior: >
80
+ $100,000+ (43)
81
+ $105,000+ (38)
82
+ $110,000+ (28)
83
+ $115,000+ (22)
84
+ $130,000+ (8)
85
+
86
+ jobs:
87
+ entry: 71
88
+ mid: 144
89
+ senior: 47
90
+
91
+ resumes: 448
92
+
93
+ java-swing:
94
+ salaries:
95
+ entry: >
96
+ $70,000+ (61)
97
+ $75,000+ (56)
98
+ $80,000+ (43)
99
+ $90,000+ (29)
100
+ $105,000+ (12)
101
+
102
+ mid: >
103
+ $85,000+ (249)
104
+ $90,000+ (223)
105
+ $100,000+ (148)
106
+ $105,000+ (117)
107
+ $115,000+ (50)
108
+
109
+ senior: >
110
+ $85,000+ (126)
111
+ $95,000+ (99)
112
+ $105,000+ (73)
113
+ $110,000+ (57)
114
+ $120,000+ (27)
115
+
116
+ jobs:
117
+ entry: 71
118
+ mid: 292
119
+ senior: 136
120
+
121
+ resumes: 23_648
122
+
123
+ java-android:
124
+ salaries:
125
+ entry: >
126
+ $70,000+ (977)
127
+ $85,000+ (785)
128
+ $95,000+ (613)
129
+ $105,000+ (398)
130
+ $115,000+ (235)
131
+
132
+ mid: >
133
+ $85,000+ (2461)
134
+ $95,000+ (2032)
135
+ $105,000+ (1451)
136
+ $110,000+ (1176)
137
+ $120,000+ (646)
138
+
139
+ senior: >
140
+ $90,000+ (896)
141
+ $100,000+ (758)
142
+ $110,000+ (563)
143
+ $120,000+ (343)
144
+ $130,000+ (181)
145
+
146
+ jobs:
147
+ entry: 1_142
148
+ mid: 2_896
149
+ senior: 1_002
150
+
151
+ resumes: 65_373
152
+
153
+ java-j2ee:
154
+ salaries:
155
+ entry: >
156
+ $70,000+ (764)
157
+ $75,000+ (688)
158
+ $85,000+ (487)
159
+ $95,000+ (322)
160
+ $105,000+ (176)
161
+
162
+ mid: >
163
+ $80,000+ (3173)
164
+ $90,000+ (2557)
165
+ $95,000+ (2142)
166
+ $100,000+ (1697)
167
+ $110,000+ (845)
168
+
169
+ senior: >
170
+ $90,000+ (1805)
171
+ $100,000+ (1412)
172
+ $105,000+ (1166)
173
+ $110,000+ (935)
174
+ $120,000+ (510)
175
+
176
+ jobs:
177
+ entry: 910
178
+ mid: 3_692
179
+ senior: 2_087
180
+
181
+ resumes: 92_525
182
+
183
+ swift-ios:
184
+ salaries:
185
+ entry: >
186
+ $65,000+ (403)
187
+ $85,000+ (340)
188
+ $95,000+ (282)
189
+ $105,000+ (196)
190
+ $115,000+ (102)
191
+
192
+ mid: >
193
+ $85,000+ (837)
194
+ $95,000+ (699)
195
+ $105,000+ (502)
196
+ $110,000+ (417)
197
+ $120,000+ (218)
198
+
199
+ senior: >
200
+ $95,000+ (235)
201
+ $105,000+ (189)
202
+ $110,000+ (159)
203
+ $120,000+ (98)
204
+ $130,000+ (47)
205
+
206
+ jobs:
207
+ entry: 471
208
+ mid: 984
209
+ senior: 267
210
+
211
+ resumes: 6_169
212
+
213
+ javascript-jquery:
214
+ salaries:
215
+ entry: >
216
+ $60,000+ (2249)
217
+ $75,000+ (1821)
218
+ $85,000+ (1404)
219
+ $95,000+ (903)
220
+ $105,000+ (453)
221
+
222
+ mid: >
223
+ $75,000+ (8387)
224
+ $85,000+ (6890)
225
+ $90,000+ (5850)
226
+ $100,000+ (3551)
227
+ $110,000+ (1685)
228
+
229
+ senior: >
230
+ $90,000+ (2352)
231
+ $95,000+ (2049)
232
+ $100,000+ (1701)
233
+ $105,000+ (1257)
234
+ $115,000+ (604)
235
+
236
+ jobs:
237
+ entry: 2_571
238
+ mid: 9_641
239
+ senior: 2_803
240
+
241
+ resumes: 123_148
242
+
243
+ php:
244
+ salaries:
245
+ entry: >
246
+ $45,000+ (4548)
247
+ $60,000+ (3761)
248
+ $75,000+ (2779)
249
+ $85,000+ (2058)
250
+ $100,000+ (1100)
251
+
252
+ mid: >
253
+ $65,000+ (9836)
254
+ $80,000+ (7749)
255
+ $90,000+ (5693)
256
+ $95,000+ (4595)
257
+ $105,000+ (2631)
258
+
259
+ senior: >
260
+ $85,000+ (2511)
261
+ $95,000+ (2116)
262
+ $105,000+ (1478)
263
+ $110,000+ (1171)
264
+ $120,000+ (629)
265
+
266
+ jobs:
267
+ entry: 5_458
268
+ mid: 11_397
269
+ senior: 2_892
270
+
271
+ resumes: 184_970
272
+
273
+ javascript-react:
274
+ salaries:
275
+ entry:
276
+ $80,000+ (622)
277
+ $90,000+ (531)
278
+ $100,000+ (380)
279
+ $110,000+ (249)
280
+ $115,000+ (174)
281
+
282
+ mid:
283
+ $90,000+ (1832)
284
+ $95,000+ (1601)
285
+ $100,000+ (1370)
286
+ $110,000+ (825)
287
+ $120,000+ (426)
288
+
289
+ senior:
290
+ $95,000+ (658)
291
+ $105,000+ (505)
292
+ $110,000+ (426)
293
+ $115,000+ (323)
294
+ $125,000+ (158)
295
+ jobs:
296
+ entry: 723
297
+ mid: 2_192
298
+ senior: 727
299
+ resumes: 4_409
300
+
301
+ javascript-angular:
302
+ salaries:
303
+ entry:
304
+ $80,000+ (1233)
305
+ $90,000+ (1029)
306
+ $95,000+ (848)
307
+ $105,000+ (502)
308
+ $115,000+ (275)
309
+
310
+ mid:
311
+ $85,000+ (4146)
312
+ $95,000+ (3285)
313
+ $100,000+ (2704)
314
+ $105,000+ (2049)
315
+ $115,000+ (1074)
316
+
317
+ senior:
318
+ $95,000+ (1435)
319
+ $100,000+ (1269)
320
+ $105,000+ (1010)
321
+ $115,000+ (568)
322
+ $125,000+ (289)
323
+
324
+ jobs:
325
+ entry: 1_453
326
+ mid: 4_725
327
+ senior: 1_641
328
+
329
+ resumes: 27_324
@@ -0,0 +1,22 @@
1
+ class Array
2
+ # File activesupport/lib/active_support/core_ext/array/grouping.rb, line 20
3
+ def in_groups_of(number, fill_with = nil)
4
+ if number.to_i <= 0
5
+ raise ArgumentError,
6
+ "Group size must be a positive integer, was #{number.inspect}"
7
+ end
8
+
9
+ if fill_with == false
10
+ collection = self
11
+ else
12
+ padding = (number - size % number) % number
13
+ collection = dup.concat(Array.new(padding, fill_with))
14
+ end
15
+
16
+ if block_given?
17
+ collection.each_slice(number) { |slice| yield(slice) }
18
+ else
19
+ collection.each_slice(number).to_a
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,9 @@
1
+
2
+ class Hash
3
+
4
+ def with_indifferent_access
5
+ ActiveSupport::HashWithIndifferentAccess.new(self)
6
+ end
7
+
8
+ alias nested_under_indifferent_access with_indifferent_access
9
+ end
@@ -0,0 +1,174 @@
1
+ require 'active_support/core_ext/hash/keys'
2
+ require 'active_support/core_ext/hash/reverse_merge'
3
+
4
+ module ActiveSupport
5
+ class HashWithIndifferentAccess < Hash
6
+ def extractable_options?
7
+ true
8
+ end
9
+
10
+ def with_indifferent_access
11
+ dup
12
+ end
13
+
14
+ def nested_under_indifferent_access
15
+ self
16
+ end
17
+
18
+ def initialize(constructor = {})
19
+ if constructor.respond_to?(:to_hash)
20
+ super()
21
+ update(constructor)
22
+ else
23
+ super(constructor)
24
+ end
25
+ end
26
+
27
+ def default(key = nil)
28
+ if key.is_a?(Symbol) && include?(key = key.to_s)
29
+ self[key]
30
+ else
31
+ super
32
+ end
33
+ end
34
+
35
+ def self.new_from_hash_copying_default(hash)
36
+ hash = hash.to_hash
37
+ new(hash).tap do |new_hash|
38
+ new_hash.default = hash.default
39
+ new_hash.default_proc = hash.default_proc if hash.default_proc
40
+ end
41
+ end
42
+
43
+ def self.[](*args)
44
+ new.merge!(Hash[*args])
45
+ end
46
+
47
+ alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
48
+ alias_method :regular_update, :update unless method_defined?(:regular_update)
49
+
50
+ def []=(key, value)
51
+ regular_writer(convert_key(key), convert_value(value, for: :assignment))
52
+ end
53
+
54
+ alias_method :store, :[]=
55
+
56
+ def update(other_hash)
57
+ if other_hash.is_a? HashWithIndifferentAccess
58
+ super(other_hash)
59
+ else
60
+ other_hash.to_hash.each_pair do |key, value|
61
+ if block_given? && key?(key)
62
+ value = yield(convert_key(key), self[key], value)
63
+ end
64
+ regular_writer(convert_key(key), convert_value(value))
65
+ end
66
+ self
67
+ end
68
+ end
69
+
70
+ alias_method :merge!, :update
71
+
72
+ def key?(key)
73
+ super(convert_key(key))
74
+ end
75
+
76
+ alias_method :include?, :key?
77
+ alias_method :has_key?, :key?
78
+ alias_method :member?, :key?
79
+
80
+ def fetch(key, *extras)
81
+ super(convert_key(key), *extras)
82
+ end
83
+
84
+ def values_at(*indices)
85
+ indices.collect { |key| self[convert_key(key)] }
86
+ end
87
+
88
+ def dup
89
+ self.class.new(self).tap do |new_hash|
90
+ set_defaults(new_hash)
91
+ end
92
+ end
93
+
94
+ def merge(hash, &block)
95
+ self.dup.update(hash, &block)
96
+ end
97
+
98
+ def reverse_merge(other_hash)
99
+ super(self.class.new_from_hash_copying_default(other_hash))
100
+ end
101
+
102
+ def reverse_merge!(other_hash)
103
+ replace(reverse_merge( other_hash ))
104
+ end
105
+
106
+ def replace(other_hash)
107
+ super(self.class.new_from_hash_copying_default(other_hash))
108
+ end
109
+
110
+ def delete(key)
111
+ super(convert_key(key))
112
+ end
113
+
114
+ def stringify_keys!; self end
115
+ def deep_stringify_keys!; self end
116
+ def stringify_keys; dup end
117
+ def deep_stringify_keys; dup end
118
+ undef :symbolize_keys!
119
+ undef :deep_symbolize_keys!
120
+ def symbolize_keys; to_hash.symbolize_keys! end
121
+ def deep_symbolize_keys; to_hash.deep_symbolize_keys! end
122
+ def to_options!; self end
123
+
124
+ def select(*args, &block)
125
+ dup.tap { |hash| hash.select!(*args, &block) }
126
+ end
127
+
128
+ def reject(*args, &block)
129
+ dup.tap { |hash| hash.reject!(*args, &block) }
130
+ end
131
+
132
+ def to_hash
133
+ _new_hash = Hash.new
134
+ set_defaults(_new_hash)
135
+
136
+ each do |key, value|
137
+ _new_hash[key] = convert_value(value, for: :to_hash)
138
+ end
139
+ _new_hash
140
+ end
141
+
142
+ protected
143
+ def convert_key(key)
144
+ key.kind_of?(Symbol) ? key.to_s : key
145
+ end
146
+
147
+ def convert_value(value, options = {})
148
+ if value.is_a? Hash
149
+ if options[:for] == :to_hash
150
+ value.to_hash
151
+ else
152
+ value.nested_under_indifferent_access
153
+ end
154
+ elsif value.is_a?(Array)
155
+ if options[:for] != :assignment || value.frozen?
156
+ value = value.dup
157
+ end
158
+ value.map! { |e| convert_value(e, options) }
159
+ else
160
+ value
161
+ end
162
+ end
163
+
164
+ def set_defaults(target)
165
+ if default_proc
166
+ target.default_proc = default_proc.dup
167
+ else
168
+ target.default = default
169
+ end
170
+ end
171
+ end
172
+ end
173
+ HashWithIndifferentAccess = ActiveSupport::HashWithIndifferentAccess
174
+
@@ -0,0 +1,184 @@
1
+ require File.join(File.dirname(__FILE__), './core_ext/array.rb')
2
+
3
+ module JobDollars
4
+ # This module contains the estimation code.
5
+ module Estimator
6
+ # Estimate value of a developer resume item.
7
+ #
8
+ # @param y (Fixnum) number of years
9
+ # @param hash (HashWithIndifferentAccess) job data for the chosen skill,
10
+ # shaped like the top-level values in langval.yml
11
+ # @return (Float) Value of resume item in dollars.
12
+ def value_of_resume_item_in_dollars(y, hash)
13
+ resu = hash[:resumes]
14
+ sala = crunch_salaries(hash)
15
+
16
+ chance = {
17
+ entry: chance_of_getting_job(y, resu, :entry),
18
+ mid: chance_of_getting_job(y, resu, :mid),
19
+ senior: chance_of_getting_job(y, resu, :senior)
20
+ }
21
+
22
+ ((chance[:entry] * sala[:entry]) +
23
+ (chance[:mid] * sala[:mid]) +
24
+ (chance[:senior] * sala[:senior])) / 3.0
25
+ end
26
+
27
+ # Estimate the work the job market does for a candidate with a certain
28
+ # number of years of experience in a given skill.
29
+ #
30
+ # @param y (Fixnum) number of years
31
+ # @param hash (HashWithIndifferentAccess) job data for the chosen skill,
32
+ # shaped like the top-level values in langval.yml
33
+ # @return (Float) Market work estimate in job-dollars.
34
+ def market_work_in_job_dollars(y, hash)
35
+ candidate_type = case
36
+ when y >= 5
37
+ :senior
38
+ when y >= 3 && y < 5
39
+ :mid
40
+ when y < 3
41
+ :entry
42
+ end
43
+
44
+ value_of_resume_item_in_dollars(y, hash) * hash[:jobs][candidate_type]
45
+ end
46
+
47
+ # Estimate the work the job market does for a candidate with a certain
48
+ # number of years of experience in a given skill, in Javagrads.
49
+ #
50
+ # @param y (Fixnum) number of years
51
+ # @param hash (HashWithIndifferentAccess) job data for the chosen skill,
52
+ # shaped like the top-level values in langval.yml
53
+ # @return (Float) Market work estimate in Javagrads.
54
+ def market_work_in_javagrads(y, hash)
55
+ market_work_in_job_dollars(y, hash) / JAVAGRAD_IN_JOB_DOLLARS
56
+ end
57
+
58
+ # Calculate the number of Javagrads of work the job market does for beginners
59
+ # (zero years of experience) with this skill.
60
+ #
61
+ # @param hash (HashWithIndifferentAccess) job data for the chosen skill,
62
+ # shaped like the top-level values in langval.yml
63
+ # @return (Float) Beginner rating in Javagrads.
64
+ def beginner_javagrad_rating(hash)
65
+ market_work_in_javagrads(0.0, hash)
66
+ end
67
+
68
+ # Get the average salary for jobs returned from an Indeed.com search,
69
+ # based on refinements sidebar text with facet totals.
70
+ #
71
+ # @param salatext (String) refinements text
72
+ # @param total (Fixnum) total number of results
73
+ # @return (Float) Average salary in dollars
74
+ def average_salary_from_indeed_facets(salatext, total)
75
+ salaries = salatext.split(/\s+/).in_groups_of(2).map { |r| r.map { |i| i.gsub(/\D/, '').to_f }}
76
+
77
+ salaries = [[salaries[0][0], total.to_f]] + salaries
78
+
79
+ salaries = salaries.map.with_index do |salary, idx|
80
+ if idx == 0
81
+ amt, count = *salary
82
+ [amt, count - salaries[1][1]]
83
+ elsif idx == salaries.size-1
84
+ salary
85
+ else
86
+ amt, count = *salary
87
+ [(amt+salaries[idx+1][0])/2, count-salaries[idx+1][1]]
88
+ end
89
+ end
90
+
91
+ salaries = salaries.map do |amt, count|
92
+ amt * count
93
+ end
94
+
95
+ salaries.inject(&:+) / total
96
+ end
97
+
98
+ NORMAL_DISTRIBUTION = {
99
+ 1 => [1.0],
100
+ 2 => [0.5,0.5],
101
+ 3 => [0.0918,0.82,0.0918],
102
+ 4 => [0.0228,0.48,0.48,0.0228],
103
+ 5 => [0.0082,0.21,0.58,0.21,0.0082],
104
+ 6 => [0.0038,0.09,0.41,0.41,0.09,0.0038],
105
+ 7 => [0.0021,0.04,0.24,0.43,0.24,0.04,0.0021],
106
+ 8 => [0.0013,0.02,0.14,0.34,0.34,0.14,0.02,0.0013],
107
+ 9 => [0.0009,0.01,0.09,0.24,0.34,0.24,0.09,0.01,0.0009],
108
+ 10 => [0.0007,0.01,0.04,0.16,0.29,0.29,0.16,0.04,0.01,0.0007],
109
+ 11 => [0.0005,0.01,0.03,0.1,0.22,0.28,0.22,0.1,0.03,0.01,0.0005]
110
+ }
111
+
112
+ # Given the total number of resumes, model the probability
113
+ # distribution that various numbers of resumes will be selected.
114
+ #
115
+ # @param total_resumes (Fixnum) Total number of resumes.
116
+ # @return (Hash<Fixnum, Float>) Probabilities keyed to the number
117
+ # of resumes selected.
118
+ def applicants_per_job_distribution(total_resumes)
119
+ max = (Math.log(total_resumes) / 1.5).to_i + 1
120
+
121
+ dist = (1..max).to_a.map do |num|
122
+ [num, NORMAL_DISTRIBUTION[max][num-1]]
123
+ end
124
+
125
+ Hash[dist]
126
+ end
127
+
128
+ # Compute the chance a candidate will get a job, given the years
129
+ # of experience, total number of resumes, and the candidate type
130
+ #
131
+ # @param years (Float) candidate years of experience
132
+ # @param total_resumes (Fixnum) total resumes
133
+ # @param type (Symbol) in [:entry, :mid, :senior]
134
+ # @return (Float) Chance the candidate will get a job
135
+ def chance_of_getting_job(years, total_resumes, type = :senior)
136
+ year_range = case
137
+ when type == :senior
138
+ [5.0, 10.0]
139
+ when type == :mid
140
+ [3.0, 5.0]
141
+ when type == :entry
142
+ [0.0, 3.0]
143
+ end
144
+
145
+ strength = [((years.to_f - year_range[0]) / (year_range[1] - year_range[0])), 1.0].min
146
+
147
+ return 0.0 if strength < 0
148
+
149
+ dist = applicants_per_job_distribution(total_resumes)
150
+ dist = dist.map do |resumes, c|
151
+ other_resumes = resumes - 1
152
+
153
+ # probability of getting the job
154
+ c * (strength ** other_resumes)
155
+ end
156
+
157
+ dist.inject(&:+)
158
+ end
159
+
160
+ # Get the salary distribution for a skill.
161
+ #
162
+ # @param hash (Hash) A hash of job data shaped like the top-level values
163
+ # in langval.yml
164
+ # @return (Hash<Symbol, Float>) {entry: Float, mid: Float, senior: Float}
165
+ def crunch_salaries(hash)
166
+ {
167
+ entry: average_salary_from_indeed_facets(hash["salaries"]["entry"], hash["jobs"]["entry"]),
168
+ mid: average_salary_from_indeed_facets(hash["salaries"]["mid"], hash["jobs"]["mid"]),
169
+ senior: average_salary_from_indeed_facets(hash["salaries"]["senior"], hash["jobs"]["senior"])
170
+ }
171
+ end
172
+
173
+ # Convert job-dollars to Javagrads.
174
+ #
175
+ # @param job_dollars (Float) Job-dollars.
176
+ # @return (Float) Javagrads, precision-1.
177
+ def to_javagrads(job_dollars)
178
+ (job_dollars / JAVAGRAD).to_f(1)
179
+ end
180
+
181
+ end
182
+ end
183
+
184
+
metadata ADDED
@@ -0,0 +1,56 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: job_dollars
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.5
5
+ platform: ruby
6
+ authors:
7
+ - Tyler Boyd
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-08-07 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A job dollar is an objective measure of the strength of the job market
14
+ for entry-level workers using a given programming language and framework. It is
15
+ a composite measure of work, like kilowatt-hours or Joules, and it measures how
16
+ much work the market has done for you.
17
+ email: tboyd47@gmail.com
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - lib/job_dollars.rb
23
+ - lib/job_dollars.yml
24
+ - lib/job_dollars/core_ext/array.rb
25
+ - lib/job_dollars/core_ext/hash.rb
26
+ - lib/job_dollars/core_ext/hash_with_indifferent_access.rb
27
+ - lib/job_dollars/estimator.rb
28
+ homepage: https://www.github.com/tb0yd/job_dollars
29
+ licenses:
30
+ - MIT
31
+ metadata: {}
32
+ post_install_message:
33
+ rdoc_options:
34
+ - "-x"
35
+ - lib/job_dollars/core_ext/*
36
+ - "-m"
37
+ - README.md
38
+ require_paths:
39
+ - lib
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ required_rubygems_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ requirements: []
51
+ rubyforge_project:
52
+ rubygems_version: 2.4.5.1
53
+ signing_key:
54
+ specification_version: 4
55
+ summary: An economic measure of the value of a programming language and framework.
56
+ test_files: []