ex_aequo 0.1.4 → 0.2.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: '0499472f115bf5da195d99bdd428ba149cdfdd9aaafa9fcc3142bed9666912c8'
4
- data.tar.gz: c5f216790f1eff9d99e779c6e2ca1560f02add2714e7e49286467bdf0a49d34a
3
+ metadata.gz: 2aaf57df3f78e7ecdd11fdf189a6dbd0942a68d9ec41213713583bebd533c5dd
4
+ data.tar.gz: 799c05c0d0b4e4f20d736de98017c960e40fc370fabbfce0d3fe5827499cdafa
5
5
  SHA512:
6
- metadata.gz: e37bb04b1113d2f9dd82736382d3616bccd46e279be3a588bbdb113a34a6788d289d4baf4e2d7c4eaed2340cd4db3b2ea0e4950c278ad6f3435ce6530b7e1e21
7
- data.tar.gz: 498f891d7209f9942a121db3d0ee7ae63f7e07399d4a0503ae2880acbf24df4795cdfdd1a75f4f2273a61268db251cf1f565aeb62fcfd6ee4435ddfdf19c6e15
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
@@ -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.4'
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.4
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
@@ -32,6 +48,8 @@ files:
32
48
  - lib/ex_aequo/kernel.rb
33
49
  - lib/ex_aequo/kernel/access.rb
34
50
  - lib/ex_aequo/kernel/fn.rb
51
+ - lib/ex_aequo/my_struct.rb
52
+ - lib/ex_aequo/my_struct/class_methods.rb
35
53
  - lib/ex_aequo/version.rb
36
54
  homepage: https://gitlab.com/robert_dober/rb_ex_aequo
37
55
  licenses:
@@ -52,7 +70,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
52
70
  - !ruby/object:Gem::Version
53
71
  version: '0'
54
72
  requirements: []
55
- rubygems_version: 3.3.7
73
+ rubygems_version: 3.3.26
56
74
  signing_key:
57
75
  specification_version: 4
58
76
  summary: Some tools