ex_aequo 0.1.3 → 0.2.0

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: 394e714f95ecbb3b54b5a264ce5be367d235fcebe7513b89d48d0491de236312
4
- data.tar.gz: 177328fccfa5fbfd1911944ac5d6a65ccf7a7315589930d91beb764e413b2c4f
3
+ metadata.gz: 2aaf57df3f78e7ecdd11fdf189a6dbd0942a68d9ec41213713583bebd533c5dd
4
+ data.tar.gz: 799c05c0d0b4e4f20d736de98017c960e40fc370fabbfce0d3fe5827499cdafa
5
5
  SHA512:
6
- metadata.gz: c929dc3f52e077403241a32d114e36f76629f62c0da14d4927b03b6845bdfba0e3a1240d5a0b4285b048e2971a5898af675b86a80c5830fb35fc404a52d343ce
7
- data.tar.gz: 2c2966155b1b3ddb5ca671105568248b8e1e1f6e1ebc205d4d91dc3582343969ecf1ca9bd56f2f7906f322011ab376047b699afea2c9925f1bedd399a32f7061
6
+ metadata.gz: c4ee1ab2d221d3fe055f3e9a4d27c76fef3237af11718a3fef986702f5a08511cb43a30a439fd3e896b8a86d785691d3aab01327dbbca8d54026f6c87292b390
7
+ data.tar.gz: e038d29057424cf6f2f45139562c060b76221eca5fe6c55eaf3ae0bb0bf58b9b68666122e11d5eedf8aff396c241b1e11f1fa87892ee710e85dd02cdfd883812
data/README.md CHANGED
@@ -3,15 +3,138 @@
3
3
  [![Gem Version](https://badge.fury.io/rb/ex_aequo.svg)](http://badge.fury.io/rb/ex_aequo)
4
4
  [![Gem Downloads](https://img.shields.io/gem/dt/ex_aequo.svg)](https://rubygems.org/gems/ex_aequo)
5
5
 
6
- # ExAequo
7
6
 
8
- gem install ex_aequo
7
+ # Some Tools
8
+
9
+ ... which tools?
10
+
11
+ Let us [speculate about](https://github.com/RobertDober/speculate_about) that:
12
+
13
+
14
+ ## Context: MyStruct
15
+
16
+ All the goodies of `OpenStruct` without the badies:
17
+
18
+ - Immutable
19
+ - Deconstructable (→ _Patternmatchable_)
20
+ - _Hashy_ Interface (`fetch`, `merge`, `slice`...)
21
+
22
+ Given an instance of `MyStruct` constructed from a `Hash`
23
+ ```ruby
24
+ require 'ex_aequo/my_struct'
25
+ let(:from_hash) { MyStruct.new(a: 1, b: 2) }
26
+ ```
27
+ And an instance constructed by a reducer
28
+ ```ruby
29
+ let(:incremented) { MyStruct.from_reduce(%i[a b c d e], 0) { _1.succ } }
30
+ ```
31
+ Then they can be accessed like a `Hash` or `OpenStruct`
32
+ ```ruby
33
+ expect(from_hash[:a]).to eq(1)
34
+ expect(from_hash.fetch(:b)).to eq(2)
35
+ expect(incremented[:e]).to eq(5)
36
+ ```
37
+
38
+ And they are immutable
39
+ ```ruby
40
+ expect { from_hash[:c] = 3 }
41
+ .to raise_error(MyStruct::ImmutableError, 'cannot change values with []= in immutable instance of MyStruct')
42
+ ```
43
+
44
+ And _mutable_ operations just create new objects
45
+ ```ruby
46
+ expect(from_hash.merge(c: 3)).to eq(MyStruct.new(a: 1, b: 2, c: 3))
47
+ expect(from_hash.to_h).to eq(a: 1, b: 2)
48
+ ```
49
+
50
+ And the _hashy_ methods observer the same interface
51
+ ```ruby
52
+ expect { from_hash.fetch(:c) }
53
+ .to raise_error(KeyError, 'key :c not found in #<MyStruct a=1, b=2> and no default given to #fetch')
54
+
55
+ expect(from_hash.fetch(:c, 42)).to eq(42)
56
+ expect(from_hash.fetch(:c) { 43 }).to eq(43)
57
+
58
+ expect(incremented.slice(:a, :c, :e)).to eq(MyStruct.new(a: 1, c: 3, e: 5))
59
+ ```
60
+
61
+ ## Context: ArgsParser and Args
62
+
63
+ An expressive, yet simple argument parser that takes full advantage of Ruby 3
64
+ and returns a modern Args struct (with modern I mean MyStruct) as a result.
65
+
66
+ Given a simple example like this on
67
+ ```ruby
68
+ let(:simple_parser) do
69
+ ExAequo::ArgsParser.new(
70
+ allowed: %w[alpha: beta: :help :verbose],
71
+ aliases: {h: :help, v: :verbose, a: :alpha}
72
+ )
73
+ end
74
+ ```
75
+
76
+ Then, as northing is required we can successfully parse empty arguments
77
+ ```ruby
78
+ result = simple_parser.parse([])
79
+
80
+ expect(result).to be_ok
81
+ expect(result.missing).to be_empty
82
+ expect(result.superflous).to be_empty
83
+ expect(result.positionals).to be_empty
84
+ expect(result.keywords).to eq(MyStruct.new)
85
+ ```
86
+
87
+ And, we can also provide allowed values (N.B. ruby sytnax is default)
88
+ ```ruby
89
+ result = simple_parser.parse(%w[alpha: 42 43])
90
+
91
+ expect(result).to be_ok
92
+ expect(result.missing).to be_empty
93
+ expect(result.superflous).to be_empty
94
+ expect(result.positionals).to eq(%w[43])
95
+ expect(result.keywords).to eq(MyStruct.new(alpha: '42'))
96
+ ```
97
+
98
+ ## Context: Colors
99
+
100
+ Given the includion of the `Color` module
101
+ ```ruby
102
+ include ExAequo::Color
103
+ ```
104
+
105
+
106
+ Then we can create ansi colored strings
107
+ ```ruby
108
+ expect(ansi(:red)).to eq("\e[31m")
109
+ ```
110
+
111
+ Or we can create 256 color strings
112
+ ```ruby
113
+ expect(ansi256(100)).to eq("\e[38;5;100m")
114
+ ```
115
+
116
+ Or we can use RGB colors
117
+ ```ruby
118
+ expect(rgb(96,32,16)).to eq("\e[38;2;96;32;16m")
119
+ expect(rgb('#602010')).to eq("\e[38;2;96;32;16m")
120
+ ```
121
+
122
+ ### Context: Colorize Helper
123
+
124
+ And
125
+ ```ruby
126
+ expect(colorize('red', ansi: :green)).to eq("\e[32mred\e[0m")
127
+ ```
128
+
129
+ Or we can omit the reset
130
+ ```ruby
131
+ expect(colorize('red', ansi: :green, reset: false)).to eq("\e[32mred")
132
+ ```
133
+
9
134
 
10
- Some Tools
11
135
 
12
136
 
13
137
 
14
- ##
15
138
 
16
139
  ## LICENSE
17
140
 
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'my_struct'
4
+
5
+ module ExAequo
6
+ class Args
7
+
8
+ attr_reader :missing, :positionals, :superflous
9
+
10
+ def add_illegal_kwd(kwd)
11
+ errors << ["Illegal kwd #{kwd}"]
12
+ end
13
+
14
+ def add_kwd(kwd, value)
15
+ # Constraint Checks would go here
16
+ @keywords[kwd.to_sym] = value
17
+ self
18
+ end
19
+
20
+ def add_positional(arg)
21
+ positionals << arg
22
+ self
23
+ end
24
+
25
+ def errors
26
+ @__errors__ ||= []
27
+ end
28
+
29
+ def keywords
30
+ MyStruct.new(@keywords)
31
+ end
32
+
33
+ def ok?
34
+ missing.empty? && errors.empty?
35
+ end
36
+
37
+ def set_flag(flag)
38
+ @keywords[flag.to_sym] = true
39
+ self
40
+ end
41
+
42
+ private
43
+
44
+ attr_reader :aliases, :allowed, :required
45
+
46
+ def initialize(aliases: [], allowed: [], required: [])
47
+ @required = required
48
+ @allowed = allowed
49
+ @required = required
50
+
51
+ @bad_syntax = false
52
+ @keywords = {}
53
+ @missing = []
54
+ @positionals = []
55
+ @superflous = []
56
+ end
57
+
58
+ end
59
+ end
60
+ # SPDX-License-Identifier: Apache-2.0
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'args'
4
+
5
+ module ExAequo
6
+ class ArgsParser
7
+
8
+ FlagRgx = %r{\A : .*}x.freeze
9
+ KwdRgx = %r{.* : \z}x.freeze
10
+ def parse(args)
11
+ result = Args.new(aliases:, allowed:, required:)
12
+ args.inject([state, result], &_parse).last
13
+ end
14
+
15
+ private
16
+
17
+ attr_reader :aliases, :allowed, :posix, :required, :state
18
+
19
+ def initialize(aliases: [], allowed: [], posix: false, required: [])
20
+ @aliases = aliases
21
+ @allowed = allowed
22
+ @posix = posix
23
+ @required = required
24
+
25
+ @state = nil
26
+ end
27
+
28
+ def _parse
29
+ ->((state, result), arg) do
30
+ case state
31
+ in nil
32
+ _parse_nil(result, arg)
33
+ in kwd
34
+ _parse_kwd(kwd, result, arg)
35
+ end
36
+ end
37
+ end
38
+
39
+ def _parse_new_flag(flag, result)
40
+ if allowed.include?(flag)
41
+ [nil, result.set_flag(flag[1..-1])]
42
+ else
43
+ [nil, result.add_illegal_kwd(flag)]
44
+ end
45
+ end
46
+
47
+ def _parse_new_kwd(kwd, result)
48
+ if allowed.include?(kwd)
49
+ [kwd[0...-1], result]
50
+ else
51
+ [nil, result.add_illegal_kwd(kwd)]
52
+ end
53
+ end
54
+
55
+ def _parse_kwd(kwd, result, arg)
56
+ [nil, result.add_kwd(kwd, arg)]
57
+ end
58
+
59
+ def _parse_nil(result, arg)
60
+ case arg
61
+ when FlagRgx
62
+ _parse_new_flag(arg, result)
63
+ when KwdRgx
64
+ _parse_new_kwd(arg, result)
65
+ else
66
+ [nil, result.add_positional(arg)]
67
+ end
68
+ end
69
+ end
70
+ end
71
+ # SPDX-License-Identifier: Apache-2.0
@@ -9,10 +9,10 @@ module ExAequo
9
9
 
10
10
  def ansi256(color, bold: false, dim: false, italic: false, underline: false)
11
11
  case color
12
- in 1..256
12
+ in 0..255
13
13
  "\e[38;5;#{color}#{postfix_modifiers(bold:, dim:, italic:, underline:)}m"
14
14
  else
15
- raise IllegalColor, "#{color.inspect} is not a color number between 1 and 256"
15
+ raise IllegalColor, "#{color.inspect} is not a color number between 0 and 255"
16
16
  end
17
17
  end
18
18
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'color/colorizer'
4
+ module ExAequo
5
+ module Colors
6
+ extend self
7
+
8
+ def ansi(text, ansi, **kwds)
9
+ ExAequo::Color::Colorizer.colorize(text, ansi:, **kwds)
10
+ end
11
+
12
+ def ansi256(text, ansi256, **kwds)
13
+ ExAequo::Color::Colorizer.colorize(text, ansi256:, **kwds)
14
+ end
15
+
16
+ def rgb(text, *args, **kwds)
17
+ if args.size == 1
18
+ ExAequo::Color::Colorizer.colorize(text, rgb: args.first, **kwds)
19
+ else
20
+ ExAequo::Color::Colorizer.colorize(text, rgb: args, **kwds)
21
+ end
22
+ end
23
+
24
+ def method_missing(name, text, **kwds)
25
+ ExAequo::Color::Colorizer.colorize(text, web: name, **kwds)
26
+ end
27
+ end
28
+ end
29
+ # SPDX-License-Identifier: Apache-2.0
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MyStruct < OpenStruct
4
+ module ClassMethods
5
+ def from_reduce(keys, acc, &reducer)
6
+ new(**_from_reduce(keys, acc, &reducer))
7
+ end
8
+
9
+ private
10
+
11
+ def _from_reduce(keys, acc, &reducer)
12
+ keys.map do |key|
13
+ reducer.(acc, key) => acc
14
+ [key, acc]
15
+ end.to_h
16
+ end
17
+ end
18
+ end
19
+ # SPDX-License-Identifier: Apache-2.0
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'my_struct/class_methods'
4
+ require 'forwarder'
5
+ class MyStruct < OpenStruct
6
+ class ImmutableError < RuntimeError; end
7
+
8
+ extend ClassMethods
9
+ extend Forwarder
10
+
11
+ # forward :fetch, to: :to_h
12
+
13
+ def[]=(*)
14
+ raise ImmutableError, "cannot change values with []= in immutable instance of #{self.class}"
15
+ end
16
+
17
+ def fetch(*args, &blk)
18
+ to_h.fetch(*args, &blk)
19
+ rescue KeyError
20
+ raise KeyError,
21
+ "key #{args.first.inspect} not found in #{self} and no default given to #fetch"
22
+ end
23
+
24
+ def merge(with)
25
+ self.class.new(to_h.merge(with.to_h))
26
+ end
27
+
28
+ def slice(*args)
29
+ self.class.new(to_h.slice(*args.flatten))
30
+ end
31
+ end
32
+ # SPDX-License-Identifier: Apache-2.0
@@ -2,7 +2,7 @@
2
2
 
3
3
  module ExAequo
4
4
  module Version
5
- VERSION = '0.1.3'
5
+ VERSION = '0.2.0'
6
6
  end
7
7
  end
8
8
  # SPDX-License-Identifier: Apache-2.0
data/lib/ex_aequo.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  module ExAequo
4
4
  end
5
+ require_relative 'ex_aequo/args_parser'
5
6
  require_relative 'ex_aequo/color'
6
7
  require_relative 'ex_aequo/version'
7
8
  # SPDX-License-Identifier: Apache-2.0
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ex_aequo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Dober
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-11-21 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2023-03-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: forwarder3
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.1.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.1.0
13
27
  description: 'Some tools
14
28
 
15
29
  '
@@ -21,6 +35,8 @@ files:
21
35
  - LICENSE
22
36
  - README.md
23
37
  - lib/ex_aequo.rb
38
+ - lib/ex_aequo/args.rb
39
+ - lib/ex_aequo/args_parser.rb
24
40
  - lib/ex_aequo/color.rb
25
41
  - lib/ex_aequo/color/ansi.rb
26
42
  - lib/ex_aequo/color/ansi256.rb
@@ -28,9 +44,12 @@ files:
28
44
  - lib/ex_aequo/color/modifiers.rb
29
45
  - lib/ex_aequo/color/rgb.rb
30
46
  - lib/ex_aequo/color/web.rb
47
+ - lib/ex_aequo/colors.rb
31
48
  - lib/ex_aequo/kernel.rb
32
49
  - lib/ex_aequo/kernel/access.rb
33
50
  - lib/ex_aequo/kernel/fn.rb
51
+ - lib/ex_aequo/my_struct.rb
52
+ - lib/ex_aequo/my_struct/class_methods.rb
34
53
  - lib/ex_aequo/version.rb
35
54
  homepage: https://gitlab.com/robert_dober/rb_ex_aequo
36
55
  licenses:
@@ -51,7 +70,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
51
70
  - !ruby/object:Gem::Version
52
71
  version: '0'
53
72
  requirements: []
54
- rubygems_version: 3.3.7
73
+ rubygems_version: 3.3.26
55
74
  signing_key:
56
75
  specification_version: 4
57
76
  summary: Some tools