cotcube-helpers 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cec4f9d660486e17a4ff9ef38f53ffd1a5089de00ecbcdadb016b80dbc4231f9
4
- data.tar.gz: 90943be69de4e059082d49070741b9689cd714a5a88a4b8ead2dea74ab4f3017
3
+ metadata.gz: d5e22624f57015916268dc4ca26ec98e2d759150ab9dc88dc3b5ceda93248148
4
+ data.tar.gz: 73628320f993e73c83423dded2880f44412174c8d1cd4dd201ace3f2c6c6e41e
5
5
  SHA512:
6
- metadata.gz: bf6306e1baaadfe9fa6f6b4533d2bfb0c31fc464ffa288368d3e47a22f76c1db7a1c48470aa83970e52752b4a911a7b60f759ee75495df43f093661274c13f0c
7
- data.tar.gz: 6ea7ccc812fd160479f9519532669db81fbf4311fcb6335b841d738bcd81c86e922c994bb005e56c543b4cf0cd3f1d7a4a92db1ad7b52e5ac4d770c6932139cb
6
+ metadata.gz: 4b7b9051f22418e8a5a17245b1a410e284bf279787f1f9d279f58083f93a588c916926badc2b2834361241d874126a3af11c36805d20afe5b34049934c16cb6b
7
+ data.tar.gz: fd0dbfb22b5b7631c5ee220de6551e1adfe9a38311afe85918598fdf86d9dd50e1028663b633c8a675853238767455504bdfa9163a466ef3e362950aa44cf064
data/.irbrc.rb CHANGED
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  def verbose_toggle
2
- irb_context.echo ? irb_context.echo = false : irb_context.echo = true
4
+ irb_context.echo = (irb_context.echo ? false : true)
3
5
  end
4
6
 
5
7
  alias vt verbose_toggle
@@ -1,3 +1,7 @@
1
+ ## 0.1.4 (December 27, 2020)
2
+ - applied cops
3
+ - added README for reduce; minor changes
4
+
1
5
  ## 0.1.3 (December 22, 2020)
2
6
  - added .reduce(bars: , to: ,*args, &block) to reduce a series of bars to a higher timeframe (though only 1hour and 1day are supported yet)
3
7
 
data/Gemfile CHANGED
@@ -1,5 +1,6 @@
1
- source "https://rubygems.org"
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
2
4
 
3
5
  # Specify your gem's dependencies in bitangent.gemspec
4
6
  gemspec
5
-
data/README.md CHANGED
@@ -12,7 +12,7 @@ Returns the array compacted--or just nil, when the result is empty?
12
12
 
13
13
  This is a rather old implementation. Most probably something I developed before I met Array#group\_by.
14
14
 
15
- ##### pairwise(&block) / triplewise(&block)
15
+ ##### pairwise(&block) / one_by_one(&block)
16
16
 
17
17
  Yields block on each consecutive pair of the array, hence returning array.size-1 results.
18
18
 
@@ -41,17 +41,18 @@ Uses the range of *date alikes* delivered to create an Array of time periods of
41
41
 
42
42
  When the step is sub-day, the periods are cleared for DST-changes.
43
43
 
44
- When ranges are nil, only periods are returned that are within the full trading hours. This is
45
- accomplished by the fact, that Sunday is wday==0. If you want to use ranges, just send a an array
44
+ When ranges are nil, only periods are returned that are within the full trading hours.
45
+
46
+ This is implemented with DateTime's propery, that Sunday is wday==0. If you want to use ranges, just send a an array
46
47
  of ranges, providing seconds starting at Sunday morning midnight. Here is the default as example:
47
48
 
48
49
  ```
49
50
  ranges ||= [
50
- 61200..143999, # Sun 5pm .. Mon 4pm
51
- 147600..230399, # Mon 5pm .. Tue 4pm
52
- 234000..316799, # ...
53
- 320400..403199,
54
- 406800..489599
51
+ 61200...144000, # Sun 5pm .. Mon 4pm
52
+ 147600...230400, # Mon 5pm .. Tue 4pm
53
+ 234000...316800, # ...
54
+ 320400...403300,
55
+ 406800...489600
55
56
  ]
56
57
  ```
57
58
 
@@ -63,18 +64,19 @@ of ranges, providing seconds starting at Sunday morning midnight. Here is the de
63
64
 
64
65
  ##### sub(minimum: 1) { [:hyper, :mega] }
65
66
 
66
- sub (should be 'subpattern', but too long) is for use in case / when statements
67
- it returns a lambda, that checks the case'd expression for matching subpattern
68
- based on the the giving minimum. E.g. 'a', 'ab' .. 'abcd' will match sub(1){'abcd'}
67
+ sub (should be 'subpattern', but too long) is for use in `case / when` statements.
68
+ It returns a lambda, that checks the *case'd* expression for matching subpatterns
69
+ based on the the giving minimum. E.g. 'a', 'ab' .. 'abcd' .. 'abcd<any_garbage> will match sub(1){'abcd'}
69
70
  but only 'abc' and 'abcd' will match sub(3){'abcd'}
70
71
 
71
- The recommended use within evaluating user input, where abbreviation of incoming commands
72
+ It is developed for evaluating user input, where abbreviation of incoming commands
72
73
  is desirable (h for hoover and hyper, what will translate to sub(2){'hoover'} and sub(2){hyper})
73
74
 
74
- To extend functionality even more, it is possible to send a group of patterns to, like
75
- sub(2){[:hyper,:mega]}, what will respond truthy to "hy" and "meg" but not to "m" or "hypo"
75
+ To extend functionality even more, it is possible to send array of patterns like
76
+ sub(2){[:hyper,:mega]}, what will respond truthy to "hy" and "meg" but not to "m" or "hypo" (sadly, you can
77
+ set `:minimum` only once).
76
78
 
77
- *paired with keystroke() it allows an easy build of an inputhandler*
79
+ *Paired with keystroke() it allows an easy build of an inputhandler.*
78
80
 
79
81
  #### SimpleOutput
80
82
 
@@ -90,7 +92,7 @@ flow like logs, to pause and continue output.
90
92
  A version of STDIN.gets, that does not wait for pressing 'enter' but instantly returns the content
91
93
  of the keystroke.
92
94
 
93
- *paired with subpattern it allows an easy build of an inputhandler*
95
+ *Paired with subpattern it allows an easy build of an InputHandler.*
94
96
 
95
97
  #### Parallelize
96
98
 
@@ -98,4 +100,8 @@ of the keystroke.
98
100
 
99
101
  Based on https://github.com/grosser/parallel, it is a quite convenient way to parallelize tasks.
100
102
 
103
+ #### Reduce
104
+
105
+ ##### reduce(bars: , to: nil, datelike: :datetime, &block)
101
106
 
107
+ Given a series resp. an array of bars (a bar is a set of contract/symbol, datelike, OHLC, volume) respresenting periods of e.g. 1.minute or 15.minutes, these are 'reduced' to an new series of a higher timeframe like hours or days. More target periods might be added in the futures.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.3
1
+ 0.1.4
@@ -9,13 +9,13 @@ Gem::Specification.new do |spec|
9
9
  spec.summary = 'Some helpers and core extensions as part of the Cotcube Suite.'
10
10
  spec.description = 'Some helpers and core extensions as part of the Cotcube Suite...'
11
11
 
12
- spec.homepage = 'https://github.com/donkeybridge/'+ spec.name
12
+ spec.homepage = "https://github.com/donkeybridge/#{spec.name}"
13
13
  spec.license = 'BSD-4-Clause'
14
14
  spec.required_ruby_version = Gem::Requirement.new('~> 2.7')
15
15
 
16
16
  spec.metadata['homepage_uri'] = spec.homepage
17
17
  spec.metadata['source_code_uri'] = spec.homepage
18
- spec.metadata['changelog_uri'] = spec.homepage + '/CHANGELOG.md'
18
+ spec.metadata['changelog_uri'] = "#{spec.homepage}/CHANGELOG.md"
19
19
 
20
20
  # Specify which files should be added to the gem when it is released.
21
21
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
@@ -28,7 +28,6 @@ Gem::Specification.new do |spec|
28
28
 
29
29
  spec.add_dependency 'activesupport'
30
30
 
31
-
32
31
  spec.add_development_dependency 'rake'
33
32
  spec.add_development_dependency 'rspec', '~>3.6'
34
33
  spec.add_development_dependency 'yard', '~>0.9'
@@ -1,3 +1,5 @@
1
+ # rubocop:disable Naming/FileName
2
+ # rubocop:enable Naming/FileName
1
3
  # frozen_string_literal: true
2
4
 
3
5
  require 'active_support'
@@ -10,24 +12,19 @@ require_relative 'cotcube-helpers/enum_ext'
10
12
  require_relative 'cotcube-helpers/hash_ext'
11
13
  require_relative 'cotcube-helpers/range_ext'
12
14
  require_relative 'cotcube-helpers/string_ext'
13
- require_relative 'cotcube-helpers/subpattern.rb'
15
+ require_relative 'cotcube-helpers/subpattern'
14
16
  require_relative 'cotcube-helpers/parallelize'
15
17
  require_relative 'cotcube-helpers/simple_output'
16
18
  require_relative 'cotcube-helpers/input'
17
19
  require_relative 'cotcube-helpers/reduce'
18
20
 
19
-
20
21
  module Cotcube
21
22
  module Helpers
23
+ module_function :sub,
24
+ :parallelize,
25
+ :reduce,
26
+ :keystroke
22
27
 
23
- module_function :sub,
24
- :parallelize,
25
- :reduce,
26
- :keystroke
27
-
28
-
29
-
30
28
  # please not that module_functions of source provided in private files must be published there
31
29
  end
32
30
  end
33
-
@@ -1,22 +1,25 @@
1
- class Array
1
+ # frozen_string_literal: true
2
2
 
3
+ # Monkey patching the Ruby Core class Array
4
+ class Array
3
5
  # returns nil if the compacted array is empty, otherwise returns the compacted array
4
- def compact_or_nil(*args, &block)
5
- return nil if self.compact == []
6
- yield self.compact
6
+ def compact_or_nil(*_args)
7
+ return nil if compact == []
8
+
9
+ yield compact
7
10
  end
8
11
 
9
12
  # sorts by a given attribute and then returns groups of where this attribute is equal
10
13
  # .... seems like some_array.group_by(&attr).values
11
14
  def split_by(attrib)
12
15
  res = []
13
- sub = []
14
- self.sort_by(&attrib).each do |elem|
15
- if sub.empty? or sub.last[attrib] == elem[attrib]
16
+ sub = []
17
+ sort_by(&attrib).each do |elem|
18
+ if sub.empty? || (sub.last[attrib] == elem[attrib])
16
19
  sub << elem
17
20
  else
18
21
  res << sub
19
- sub = [ elem ]
22
+ sub = [elem]
20
23
  end
21
24
  end
22
25
  res << sub
@@ -37,7 +40,7 @@ class Array
37
40
  end.compact
38
41
  end
39
42
 
40
- alias_method :one_by_one, :pairwise
43
+ alias one_by_one pairwise
41
44
 
42
45
  # same as pairwise, but with arity of three
43
46
  def triplewise(&block)
@@ -47,7 +50,7 @@ class Array
47
50
  each_with_index.map do |_, i|
48
51
  next if i < 2
49
52
 
50
- block.call(self[i - 2], self[i-1], self[i])
53
+ block.call(self[i - 2], self[i - 1], self[i])
51
54
  end.compact
52
55
  end
53
56
  end
@@ -1,11 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Monkey patching the Ruby Core class Enumerator
1
4
  class Enumerator
2
5
  def shy_peek
3
6
  begin
4
- ret = self.peek
5
- rescue
7
+ ret = peek
8
+ rescue StandardError
6
9
  ret = nil
7
10
  end
8
11
  ret
9
12
  end
10
13
  end
11
-
@@ -1,14 +1,16 @@
1
- class Hash
1
+ # frozen_string_literal: true
2
2
 
3
+ # Monkey patching the Ruby Core class Hash
4
+ class Hash
3
5
  def keys_to_sym
4
- self.keys.each do |key|
6
+ each_key do |key|
5
7
  case self[key].class.to_s
6
- when "Hash"
8
+ when 'Hash'
7
9
  self[key].keys_to_sym
8
- when "Array"
9
- self[key].map {|el| el.is_a?(Hash) ? el.keys_to_sym : el}
10
+ when 'Array'
11
+ self[key].map { |el| el.is_a?(Hash) ? el.keys_to_sym : el }
10
12
  end
11
- self[key.to_sym] = self.delete(key)
13
+ self[key.to_sym] = delete(key)
12
14
  end
13
15
  self
14
16
  end
@@ -1,40 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Top level comment missing!
1
4
  module Cotcube
5
+ # noinspection ALL
2
6
  module Helpers
3
7
  def keystroke(quit: false)
4
8
  begin
5
9
  # save previous state of stty
6
10
  old_state = `stty -g`
7
11
  # disable echoing and enable raw (not having to press enter)
8
- system "stty raw -echo"
9
- c = STDIN.getc.chr
12
+ system 'stty raw -echo'
13
+ c = $stdin.getc.chr rescue '_' # rubocop:disable Style/RescueModifier
10
14
  # gather next two characters of special keys
11
- if(c=="\e")
12
- extra_thread = Thread.new{
13
- c = c + STDIN.getc.chr
14
- c = c + STDIN.getc.chr
15
- }
15
+ if c == "\e"
16
+ extra_thread = Thread.new do
17
+ c += $stdin.getc.chr
18
+ c += $stdin.getc.chr
19
+ end
16
20
  # wait just long enough for special keys to get swallowed
17
21
  extra_thread.join(0.00001)
18
22
  # kill thread so not-so-long special keys don't wait on getc
19
23
  extra_thread.kill
20
24
  end
21
- rescue => ex
22
- puts "#{ex.class}: #{ex.message}"
23
- puts ex.backtrace
25
+ rescue StandardError => e
26
+ puts "#{e.class}: #{e.message}"
27
+ puts e.backtrace
24
28
  ensure
25
29
  # restore previous state of stty
26
30
  system "stty #{old_state}"
27
31
  end
28
- c.each_byte do |x|
32
+ c.each_byte do |x| # rubocop:disable Lint/UnreachableLoop
29
33
  case x
30
34
  when 3
31
- puts "Strg-C captured, exiting..."
35
+ puts 'Strg-C captured, exiting...'
32
36
  quit ? exit : (return true)
33
37
  when 13
34
- return "_return_"
38
+ return '_return_'
35
39
  when 27
36
- puts "ESCAPE gathered"
37
- return "_esc_"
40
+ puts 'ESCAPE gathered'
41
+ return '_esc_'
38
42
  else
39
43
  return c
40
44
  end
@@ -1,30 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ # TODO: Missing top level documentation!
1
4
  module Cotcube
5
+ # TODO: Missing top level documentation!
2
6
  module Helpers
3
-
4
- def parallelize(ary, processes: 1, threads: 1, progress: "", &block)
5
- chunks = []
6
- if [0,1].include? processes
7
- result = Parallel.map(ary, in_threads: threads) {|u| v = yield(u); v}
8
- elsif [0,1].include?(threads)
9
- result = Parallel.map(ary, in_processes: processes) {|u| v = yield(u)}
7
+ def parallelize(ary, processes: 1, threads: 1, progress: '', &block)
8
+ chunks = []
9
+ if [0, 1].include? processes
10
+ result = Parallel.map(ary, in_threads: threads) { |u, &in_thread| in_thread.call(u) }
11
+ elsif [0, 1].include?(threads)
12
+ result = Parallel.map(ary, in_processes: processes) { |u, &in_process| in_process.call(u) }
10
13
  else
11
- ary.each_slice(threads) {|chunk| chunks << chunk }
12
- if progress == ""
13
- result = Parallel.map(chunks, :in_processes => processes) do |chunk|
14
- Parallel.map(chunk, in_threads: threads) do |unit|
15
- yield(unit)
16
- end
17
- end
18
- else
19
- result = Parallel.map(chunks, :progress => progress, :in_processes => processes) do |chunk|
20
- Parallel.map(chunk, in_threads: threads) do |unit|
21
- yield(unit)
22
- end
23
- end
24
- end
14
+ ary.each_slice(threads) { |chunk| chunks << chunk }
15
+ result = if progress == ''
16
+ Parallel.map(chunks, in_processes: processes) do |chunk|
17
+ Parallel.map(chunk, in_threads: threads, &block)
18
+ end
19
+ else
20
+ Parallel.map(chunks, progress: progress, in_processes: processes) do |chunk|
21
+ Parallel.map(chunk, in_threads: threads, &block)
22
+ end
23
+ end
25
24
  end
26
25
  result
27
26
  end
28
-
29
27
  end
30
28
  end
@@ -1,52 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Monkey patching the Ruby Core class Range
1
4
  class Range
2
- def to_time_intervals(timezone: Time.find_zone('America/Chicago'), step:, ranges: nil)
5
+ def to_time_intervals(step:, timezone: Time.find_zone('America/Chicago'), ranges: nil)
6
+ unless step.is_a? ActiveSupport::Duration
7
+ raise ArgumentError,
8
+ ":step must be a 'ActiveSupport::Duration', like '15.minutes', but '#{step}' is a '#{step.class}'"
9
+ end
3
10
 
4
- raise ArgumentError, ":step must be a 'ActiveSupport::Duration', like '15.minutes', but '#{step}' is a '#{step.class}'" unless step.is_a? ActiveSupport::Duration
11
+ valid_classes = [ActiveSupport::TimeWithZone, Time, Date, DateTime]
12
+ unless timezone.is_a? ActiveSupport::TimeZone
13
+ raise "Expecting 'ActiveSupport::TimeZone' for :timezone, got '#{timezone.class}"
14
+ end
5
15
 
6
- valid_classes = [ ActiveSupport::TimeWithZone, Time, Date, DateTime ]
7
- raise "Expecting 'ActiveSupport::TimeZone' for :timezone, got '#{timezone.class}" unless timezone.is_a? ActiveSupport::TimeZone
8
16
  starting = self.begin
9
17
  ending = self.end
10
18
  starting = timezone.parse(starting) if starting.is_a? String
11
19
  ending = timezone.parse(ending) if ending.is_a? String
12
- raise ArgumentError, ":self.begin seems not to be proper time value: #{starting} is a #{starting.class}" unless valid_classes.include? starting.class
13
- raise ArgumentError, ":self.end seems not to be proper time value: #{ending} is a #{ending.class}" unless valid_classes.include? ending.class
20
+ unless valid_classes.include? starting.class
21
+ raise ArgumentError,
22
+ ":self.begin seems not to be proper time value: #{starting} is a #{starting.class}"
23
+ end
24
+ unless valid_classes.include? ending.class
25
+ raise ArgumentError,
26
+ ":self.end seems not to be proper time value: #{ending} is a #{ending.class}"
27
+ end
14
28
 
15
- ##### The following is the actual big magic line:
16
- #
17
- result = (starting.to_time.to_i..ending.to_time.to_i).step(step).to_a.map{|x| timezone.at(x)}
29
+ ##### The following is the actual big magic line, as it creates the raw target array:
18
30
  #
19
- ####################<3
20
-
31
+ result = (starting.to_time.to_i..ending.to_time.to_i).step(step).to_a.map { |x| timezone.at(x) }
32
+ #
33
+ # ###################<3##
21
34
 
22
35
  # with step.to_i >= 86400 we are risking stuff like 25.hours to return bogus
23
36
  # also notice: When using this with swaps, you will loose 1 hour (#f**k_it)
24
37
  #
25
38
  # eventually, for dailies and above, return M-F default, return S-S when forced by empty ranges
26
- return result.select{|x| (not ranges.nil? and ranges.empty?) ? true : (not [6,0].include?(x.wday)) } if step.to_i >= 86400
39
+ if step.to_i >= 86_400
40
+ return result.select do |x|
41
+ (not ranges.nil?) && ranges.empty? ? true : (not [6, 0].include?(x.wday))
42
+ end
43
+ end
27
44
 
28
45
  # sub-day is checked for DST and filtered along provided ranges
29
46
  starting_with_dst = result.first.dst?
30
- seconds_since_sunday_morning = lambda {|x| x.wday * 86400 + x.hour * 3600 + x.min * 60 + x.sec}
47
+
48
+ # The following lambda is completely misplaces here.
49
+ # It should probably relocated to Cotcube::Bardata
50
+ # NOTE: In this current version 12 belongs to it succeeding hour
51
+ # i.e. 12am is right before 1am and 12pm right before 1pm
52
+ convert_to_sec_since = lambda do |clocking|
53
+ from_src, to_src = clocking.split(' - ')
54
+ regex = /^(?<hour>\d+):(?<minute>\d+)(?<morning>[pa]).?m.*/
55
+
56
+ from = from_src.match(regex)
57
+ to = to_src.match(regex)
58
+
59
+ from_i = from[:hour].to_i * 3600 + from[:minute].to_i * 60 + (from[:morning] == 'a' ? 2 : 1) * 12 * 3600
60
+ to_i = to[:hour].to_i * 3600 + to[:minute].to_i * 60 + (to[:morning] == 'a' ? 2 : 3) * 12 * 3600
61
+
62
+ (0...5).to_a.map { |i| [from_i + i * 24 * 3600, to_i + i * 24 * 3600] }
63
+ end
64
+ convert_to_sec_since.call('9:00a.m - 5:00p.m.')
65
+
66
+ seconds_since_sunday_morning = ->(x) { x.wday * 86_400 + x.hour * 3600 + x.min * 60 + x.sec }
31
67
  ranges ||= [
32
- 61200..143999, # Sun 5pm .. Mon 4pm
33
- 147600..230399, # Mon 5pm .. Tue 4pm
34
- 234000..316799, # ...
35
- 320400..403199,
36
- 406800..489599
68
+ 61_200...144_000, # Sun 5pm .. Mon 4pm
69
+ 147_600...230_400, # Mon 5pm .. Tue 4pm
70
+ 234_000...316_800, # ...
71
+ 320_400...403_200,
72
+ 406_800...489_600
37
73
  ]
38
74
 
39
- # if there was a change towards daylight saving time, substract 1 hour, otherwise add 1 hour
75
+ # if there was a change towards daylight saving time, subtract 1 hour, otherwise add 1 hour
40
76
  result.map! do |time|
41
- if not starting_with_dst and time.dst?
42
- time - 3600
43
- elsif starting_with_dst and not time.dst?
44
- time + 3600
77
+ if (not starting_with_dst) && time.dst?
78
+ time - 3600
79
+ elsif starting_with_dst && (not time.dst?)
80
+ time + 3600
45
81
  else
46
- time
82
+ time
47
83
  end
48
84
  end
49
- return result if ranges.empty?
50
- result.select{|x| ranges.map{|r| r.include? seconds_since_sunday_morning.call(x)}.reduce(:|) }
85
+ return result if ranges.empty?
86
+
87
+ result.select { |x| ranges.map { |r| r.include? seconds_since_sunday_morning.call(x) }.reduce(:|) }
51
88
  end
52
89
  end
@@ -1,39 +1,52 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Cotcube
4
+ # Missing top level documentation
2
5
  module Helpers
3
- def reduce(bars: , to: nil, datelike: :datetime, &block)
4
- terminators = case to
5
- when 1.day
6
- [:last, :beginning_of_day]
7
- when 1.hour
8
- [:first, :beginning_of_hour]
9
- else
10
- raise ArgumentError, "Currently supported are reductions to '1.hour' and '1.day'"
11
- end
12
- determine_datelike = lambda {|ary| ary.send(terminators.first)[datelike].send(terminators.last) }
13
- make_new_bar = lambda do |ary, date = nil|
14
- result = {
15
- symbol: ary.first[:symbol],
16
- datetime: determine_datelike.call(ary),
17
- day: ary.first[:day],
18
- open: ary.first[:open],
19
- high: ary.map{|x| x[:high]}.max,
20
- low: ary.map{|x| x[:low]}.min,
21
- close: ary.last[:close],
22
- volume: ary.map{|x| x[:volume]}.reduce(:+)
23
- }
24
- result.map{|k,v| result.delete(k) if v.nil?}
25
- result
6
+ def reduce(bars:, to: nil, date_alike: :datetime, &block)
7
+ case to
8
+ when :days
9
+ terminators = %i[last daily beginning_of_day]
10
+ block = proc { |c, b| c[:day] == b[:day] } unless block_given?
11
+ when :hours
12
+ terminators = %i[first hours beginning_of_hour]
13
+ block = proc { |c, b| c[:day] == b[:day] and c[:datetime].hour == b[:datetime].hour } unless block_given?
14
+ when :weeks
15
+ terminators = %i[first weeks beginning_of_week]
16
+ block = proc { |a, b| a[:datetime].to_datetime.cweek == b[:datetime].to_datetime.cweek } unless block_given?
17
+ when :months
18
+ terminators = %i[first months beginning_of_month]
19
+ block = proc { |a, b| a[:datetime].to_datetime.month == b[:datetime].to_datetime.month } unless block_given?
20
+ else
21
+ raise ArgumentError, 'Currently supported are reductions to :hours, :days, :weeks, :months '
22
+ end
23
+ determine_date_alike = ->(ary) { ary.send(terminators.first)[date_alike].send(terminators.last) }
24
+ make_new_bar = lambda do |ary, _date = nil|
25
+ result = {
26
+ contract: ary.first[:contract],
27
+ symbol: ary.first[:symbol],
28
+ datetime: determine_date_alike.call(ary),
29
+ day: ary.first[:day],
30
+ open: ary.first[:open],
31
+ high: ary.map { |x| x[:high] }.max,
32
+ low: ary.map { |x| x[:low] }.min,
33
+ close: ary.last[:close],
34
+ volume: ary.map { |x| x[:volume] }.reduce(:+),
35
+ type: terminators[1]
36
+ }
37
+ result.map { |k, v| result.delete(k) if v.nil? }
38
+ result
26
39
  end
27
- collector = [ ]
28
- final = [ ]
40
+ collector = []
41
+ final = []
29
42
  bars.each do |bar|
30
- if collector.empty? or block.call(collector.last, bar)
31
- collector << bar
32
- else
43
+ if collector.empty? || block.call(collector.last, bar)
44
+ collector << bar
45
+ else
33
46
  new_bar = make_new_bar.call(collector)
34
- final << new_bar
35
- collector = [ bar ]
36
- end
47
+ final << new_bar
48
+ collector = [bar]
49
+ end
37
50
  end
38
51
  new_bar = make_new_bar.call(collector)
39
52
  final << new_bar
@@ -41,4 +54,3 @@ module Cotcube
41
54
  end
42
55
  end
43
56
  end
44
-
@@ -1,9 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Monkey patching the Ruby Core class String
1
4
  class String
2
- def is_valid_json?
3
- JSON.parse(self)
4
- return true
5
- rescue JSON::ParserError => e
6
- return false
5
+ # ...
6
+ def valid_json?
7
+ JSON.parse(self)
8
+ true
9
+ rescue JSON::ParserError
10
+ false
7
11
  end
8
- end
9
12
 
13
+ alias is_valid_json? valid_json?
14
+ end
@@ -1,11 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # ...
3
4
  module Cotcube
5
+ # ...
4
6
  module Helpers
5
7
  # sub (should be 'subpattern', but too long) is for use in case / when statements
6
8
  # it returns a lambda, that checks the case'd expression for matching subpattern
7
9
  # based on the the giving minimum. E.g. 'a', 'ab' .. 'abcd' will match sub(1){'abcd'}
8
- # but only 'abc' and 'abcd' will match sub(3){'abcd'}
10
+ # but only 'abc' and 'abcd' will match sub(3){'abcd'}.:
9
11
  #
10
12
  # The recommended use within evaluating user input, where abbreviation of incoming commands
11
13
  # is desirable (h for hoover and hyper, what will translate to sub(2){'hoover'} and sub(2){hyper})
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cotcube-helpers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Benjamin L. Tischendorf
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-12-22 00:00:00.000000000 Z
11
+ date: 2020-12-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport