such 2.0.210201 → 2.1.230106

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: 84767a253e3e1535798068135516617e3c198fc4b3ed756e529c16c27f25a649
4
- data.tar.gz: 919ffcc84f13208bb3fc232ad8dc2ac92eb16b40d0cc6f63bb81b2b79c8b7e63
3
+ metadata.gz: c296ea57df2d19bf9db70eb35f97494e15b8c739d5b0e8cea5a31163c457dc76
4
+ data.tar.gz: a1c10cf419d67311a9b9e33fdf26a3f587052af4a5a3260a6b3f2db90b255056
5
5
  SHA512:
6
- metadata.gz: d53f03a3dc85ad766199e40d0f7d08011420ec1c437de865cdda76f2757a8c4bac012379098fd087af1f78ce11918be949b46fe0cff68668806df237a175a5f0
7
- data.tar.gz: 96c391adf17465cdf4330a37c83eece66a1d4ae37337067fc8b04cd1f0105fe5f4b45b4863371c60d558552980e5ab744f9cb817c4c26322895b50139567760a
6
+ metadata.gz: 23fd64fe227f2fb0fd3e3ac26c512a754fbf19b047a90ca21e0e12bc807309642543e614cc33b88a5aee46c6efe2f06fc4ea06d7881cf59d25346c3acd44af1d
7
+ data.tar.gz: 8907935ccdea95e257bda042ac851fdcacdb0d9b8972e8f43d1d4fd1e071d514f59001d7e5557c0d864b4f17c6813e1d77b3a2047a20b866c032bf14b3766723
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Such
2
2
 
3
- * [VERSION 2.0.210201](https://github.com/carlosjhr64/such/releases)
3
+ * [VERSION 2.1.230106](https://github.com/carlosjhr64/such/releases)
4
4
  * [github](https://www.github.com/carlosjhr64/such)
5
5
  * [rubygems](https://rubygems.org/gems/such)
6
6
 
@@ -12,13 +12,10 @@ Can be used to wrap any class with the alternate constructor,
12
12
  although targeted only Gtk3 widgets.
13
13
 
14
14
  ## INSTALL:
15
-
16
15
  ```shell
17
- $ sudo gem install such
16
+ $ gem install such
18
17
  ```
19
-
20
18
  ## SYNOPSIS:
21
-
22
19
  ```ruby
23
20
  require 'gtk3'
24
21
  require 'such'
@@ -38,13 +35,11 @@ window.show_all
38
35
 
39
36
  Gtk.main #=> nil
40
37
  ```
41
-
42
38
  ## MORE:
43
39
 
44
- Arrays are passed to constructer's super,
40
+ Arrays are passed to constructor's super,
45
41
  Hashes are method=>arguments pairs, and Strings are signals.
46
42
  Other objects are assumed to be containers:
47
-
48
43
  ```ruby
49
44
  Such::Button.new(
50
45
  window,
@@ -60,17 +55,13 @@ window.add button
60
55
  button.set_size_request 100, 50
61
56
  button.signal_connect('clicked'){puts 'OK'}
62
57
  ```
63
-
64
58
  To set the packing method to say `:pack_start`, set the `:into` method as follows:
65
-
66
59
  ```ruby
67
60
  {into: [:pack_start, expand:false, fill:false, padding:0]}
68
- # The effect in the contructor will be as if the following was run:
61
+ # The effect in the constructor will be as if the following was run:
69
62
  # container.pack_start(self, expand:false, fill:false, padding:0)
70
63
  ```
71
-
72
64
  One can configure Symbol keys to represent metadata about a widget:
73
-
74
65
  ```ruby
75
66
  Thing.configure(
76
67
  KEY: [ arg1, arg2, arg3 ], # an array for super(arg1, arg2, arg3)
@@ -82,8 +73,7 @@ One can configure Symbol keys to represent metadata about a widget:
82
73
  key!: [[arg1, arg2], {meth1:args1, meth2:args2}, 'signal1', 'signal2'] # the splatter bang!
83
74
  )
84
75
  ```
85
-
86
- The examples in this repository are reworks of the examples given in
76
+ Many examples in this repository are reworks of the examples given in
87
77
  ZetCode.com[http://zetcode.com/gui/rubygtk/] (back in 2015).
88
78
 
89
79
  ## Features:
@@ -93,19 +83,26 @@ ZetCode.com[http://zetcode.com/gui/rubygtk/] (back in 2015).
93
83
  * Missing signal assumed to be 'clicked'
94
84
  * Heuristics on when one wants to iterate a method over the arguments given
95
85
  * Packing method defaults (ultimately) to :add
96
- * Way to change default packing behaviour
86
+ * Way to change default packing behavior
97
87
 
98
88
  ## But wait! One more thing:
99
89
 
100
90
  See [such_parts_demo](examples/such_parts_demo) in the examples directory
101
- and [tc_part](test/tc_part) for hints on how to use the powerful
91
+ and [tc_part](test/tc_part) for hints on how to use
102
92
  [Such::Part module](lib/such/part.rb).
103
93
 
94
+ See also [tc_convention](test/tc_convention) in the test directory
95
+ for a suggested convention for naming keys.
96
+
97
+ ## Gnarly!
98
+
99
+ Yes, I know!
100
+
104
101
  ## LICENSE:
105
102
 
106
103
  (The MIT License)
107
104
 
108
- Copyright (c) 2021 CarlosJHR64
105
+ Copyright (c) 2023 CarlosJHR64
109
106
 
110
107
  Permission is hereby granted, free of charge, to any person obtaining
111
108
  a copy of this software and associated documentation files (the
@@ -0,0 +1,99 @@
1
+ # Use this to validate your configuration against the given convention.
2
+ # It should be run as part of your tests,
3
+ # not necessarily in your application.
4
+ module Such
5
+ module Convention
6
+ module Refinements
7
+ refine Object do
8
+ # Atoms
9
+ def item_symbol?
10
+ is_a?Symbol and match?(/^\w+[!?]?$/)
11
+ end
12
+ def item_boolean?
13
+ [TrueClass,FalseClass].any?{is_a?_1}
14
+ end
15
+ def item_value?
16
+ [String,Float,Integer].any?{is_a?_1}
17
+ end
18
+ # Item
19
+ def item_tangible?
20
+ item_value? or item_symbol?
21
+ end
22
+ def item?
23
+ item_tangible? or item_boolean?
24
+ end
25
+ # Items
26
+ def items?
27
+ item? or item_array? or item_hash?
28
+ end
29
+ def item_hash?
30
+ is_a?Hash and all?{_1.item_symbol? and (_2.nil? or _2.items?)}
31
+ end
32
+ def item_array?
33
+ is_a?Array and all?{_1.nil? or _1.items?}
34
+ end
35
+ def item_bang_array?
36
+ is_a?Array and
37
+ all?{_1.is_a?Symbol or _1.is_a?String or
38
+ _1.item_array? or _1.item_hash?}
39
+ end
40
+ def item_explicit_array?
41
+ is_a?Array and
42
+ all?{_1.is_a?String or _1.item_array? or _1.item_hash?}
43
+ end
44
+ end
45
+ end
46
+
47
+ CAPS = /^[A-Z_]+$/
48
+ CAPS1 = /^[A-Z_]+!$/
49
+ CAPS2 = /^[A-Z_]+[?]$/
50
+ LOWER = /^[a-z_]+$/
51
+ LOWER1 = /^[a-z_]+!$/
52
+ LOWER2 = /^[a-z_]+[?]$/
53
+ WORD = /^\w+$/
54
+ WORD1 = /^\w+!$/
55
+ WORD2 = /^\w+[?]$/
56
+
57
+ using Refinements
58
+
59
+ def self.validate_kv(k,v)
60
+ raise 'unrecognized item symbol' unless k.item_symbol?
61
+ case k
62
+ when LOWER # abc
63
+ raise 'unrecognized item hash' unless v.item_hash? or
64
+ (v.is_a?Symbol and LOWER.match?v)
65
+ when CAPS # ABC
66
+ raise 'unrecognized item array' unless v.item_array?
67
+ when WORD # Abc
68
+ raise 'unrecognized item tangible' unless v.item_tangible?
69
+ when LOWER1 # abc!
70
+ raise 'unrecognized bang array' unless v.item_bang_array?
71
+ when CAPS1 # ABC!
72
+ raise 'unrecognized explicit array' unless v.item_explicit_array?
73
+ when WORD1 # Abc!
74
+ raise 'unrecognized items' unless v.items?
75
+ when LOWER2 # abc?
76
+ raise 'unrecognized boolean' unless v.item_boolean?
77
+ when CAPS2 # ABC?
78
+ raise 'unrecognized boolean|nil' unless v.nil? or v.item_boolean?
79
+ when WORD2 # Abc?
80
+ raise 'unrecognized item value|nil' unless v.nil? or v.item_tangible?
81
+ else
82
+ raise 'should not happen'
83
+ end
84
+ end
85
+
86
+ def self.validate(config)
87
+ raise 'expected hash' unless config.is_a?Hash
88
+ errors = {}
89
+ config.each do |k,v|
90
+ begin
91
+ validate_kv(k,v)
92
+ rescue
93
+ errors[k] = $!.message
94
+ end
95
+ end
96
+ return errors.empty? ? nil : errors
97
+ end
98
+ end
99
+ end
data/lib/such/part.rb CHANGED
@@ -6,18 +6,27 @@ module Such
6
6
  super(*parameters)
7
7
  self.class.plugs.each do |plg|
8
8
  if md = PLUG_PATTERN.match(plg)
9
- plg, sym, cls = "#{plg}=".to_sym, "#{md[:sym]}!".to_sym, Object.const_get("Such::#{md[:cls]}")
9
+ plg,sym,cls = "#{plg}=".to_sym,
10
+ "#{md[:sym]}!".to_sym,
11
+ Object.const_get("Such::#{md[:cls]}")
10
12
  # self.<plg> = Such::<cls>.new(self, :<sym>!, &block)
11
13
  public_send plg, cls.new(self, sym, &block)
12
14
  end
13
15
  end
14
16
  end
15
17
 
18
+ # Each part\Such::Part can invoke `message` on each of its connected part,
19
+ # and so on...
20
+ # Any part can override its `message` method to act as a terminal node or
21
+ # modify its relay behavior.
16
22
  def message(*parameters)
17
23
  self.class.plugs.each{|plg| public_send(plg).message(*parameters) }
18
24
  end
19
25
 
20
- def method_missing(maybe,*args) # maybe a plug down the plugged things.
26
+ # Maybe a plug down the plugged things responds?
27
+ # This is a search through the connections which
28
+ # returns the first(non-nil) response.
29
+ def method_missing(maybe,*args)
21
30
  super unless args.length==0 and PLUG_PATTERN.match?(maybe)
22
31
  self.class.plugs.each do |plug|
23
32
  thing = public_send(plug)
data/lib/such/parts.rb CHANGED
@@ -1,22 +1,43 @@
1
1
  module Such
2
2
  module Parts
3
+ ### Such::Parts ###
4
+ # Signature:
5
+ # Such::Parts.make(part\Symbol, thing\Such::Thing, plugs\Array(Symbol)) \
6
+ # (Such::Thing+Such::Part)
7
+ # The name of the Such::Part sub-class will be part.
8
+ # It will be a sub-class of thing(a sub-class of Such::Thing).
9
+ # The Array of symbols, plugs, will be accessors to other connected Such::Part's.
10
+ # Each plug must match:
11
+ # /^<Part config key!>_<Name of connected sub-classed super-class>$/
12
+ # Note that these plugs are `attr_accessor`s,.
13
+ # Exemplar:
14
+ # Component0#initialize(...,&block_given)
15
+ # ...
16
+ # part_obj.key_Component1 = Component1.new(:key!,&block_given)
17
+ # ...
18
+ # Note that all connected components share the same block_given:
19
+ # block_given(part\Such::Part, *w, signal\String)
20
+ # It gets called when the part receives its assigned activation signal,
21
+ # like "clicked" for a Button.
3
22
  def self.make(part, thing, *plugs)
4
23
  unless thing < Such::Thing and [part,*plugs].all?{_1.is_a? Symbol}
5
- raise "Expected Such::Parts.make(Symbol part, Class thing < Such::Thing, *Symbol plugs)"
24
+ raise "Expected Such::Parts.make(Symbol part, " +
25
+ "Class thing < Such::Thing, *Symbol plugs)"
6
26
  end
7
27
  plugs.each do |plug|
8
- if /^[^\W_]+_(?<klass>[^\W_]+)$/=~plug
28
+ if /^[^\W_]+_(?<super_class>[^\W_]+)$/=~plug
9
29
  next unless $VERBOSE
10
- unless Object.const_defined?("Such::#{klass}")
11
- $stderr.puts "Warning: Such::#{klass} not defined yet."
30
+ unless Object.const_defined?("Such::#{super_class}")
31
+ $stderr.puts "Warning: Such::#{super_class} not defined yet."
12
32
  end
13
33
  else
14
34
  raise "Plugs must have the form key_class: #{plug}"
15
35
  end
16
36
  end
17
- subklass = Such.subclass(part, thing, include: Such::Part, attr_accessor: plugs)
18
- subklass.singleton_class.class_eval{ define_method(:plugs){plugs} }
19
- return subklass
37
+ sub_class = Such.subclass(part, thing,
38
+ include: Such::Part, attr_accessor: plugs)
39
+ sub_class.singleton_class.class_eval{ define_method(:plugs){plugs} }
40
+ return sub_class
20
41
  end
21
42
  end
22
43
  end
data/lib/such/such.rb CHANGED
@@ -1,8 +1,13 @@
1
1
  module Such
2
- def self.subclass(name, klass, **kw, &block)
3
- subklass = const_set(name, Class.new(klass))
4
- kw.each{|method, args| subklass.public_send(method, *args)}
5
- subklass.class_eval(&block) if block
6
- return subklass
2
+ def self.subclass(name, super_class, **including, &block)
3
+ # See documentation for Class#new
4
+ sub_class = const_set(name, Class.new(super_class))
5
+ # To be able to say like:
6
+ # include Such::Thing
7
+ # attr_accessor :attribute2, :attribute2
8
+ including.each{|these, mods| sub_class.public_send(these, *mods)}
9
+ # And to explicitly define methods in the subclass:
10
+ sub_class.class_eval(&block) if block
11
+ return sub_class
7
12
  end
8
13
  end
data/lib/such/thing.rb CHANGED
@@ -5,7 +5,7 @@ module Such
5
5
 
6
6
  # PARAMETERS' pretense of being a Hash constant :P
7
7
  @@PARAMETERS = {}
8
- PARAMETERS = lambda{|k| @@PARAMETERS[k]}
8
+ PARAMETERS = lambda{@@PARAMETERS[_1]}
9
9
  def PARAMETERS.to_h = @@PARAMETERS
10
10
  def self.configure(conf)
11
11
  @@PARAMETERS = conf
@@ -61,7 +61,7 @@ module Such
61
61
  end
62
62
 
63
63
  def self.which_method(container, methods=INTOS)
64
- mthd = methods.detect{|m| container.respond_to?(m)}
64
+ mthd = methods.detect{container.respond_to?_1}
65
65
  raise "Don't know how to put into #{container.class}." if mthd.nil?
66
66
  return mthd
67
67
  end
@@ -69,7 +69,7 @@ module Such
69
69
  def self.into(obj, container=nil, mthd=nil, *args)
70
70
  if container
71
71
  if mthd
72
- unless mthd.class==Symbol and container.respond_to?(mthd)
72
+ unless container.respond_to?(mthd)
73
73
  raise "Need container & method. Got #{container.class}##{mthd}(#{obj.class}...)"
74
74
  end
75
75
  else
@@ -90,7 +90,7 @@ module Such
90
90
  rescue ArgumentError, TypeError
91
91
  # Assume user meant to iterate. Note that the heuristic is not perfect.
92
92
  $stderr.puts "# Iterated Method #{mthd}." if $VERBOSE
93
- [*args].each{|arg| m.call(*arg)}
93
+ [*args].each{m.call(*_1)}
94
94
  end
95
95
  end
96
96
 
@@ -105,9 +105,8 @@ module Such
105
105
 
106
106
  def self.do_links(obj, signals, block)
107
107
  return if signals.first==''
108
- none = (signals.length==0)
109
108
  if block
110
- signals.push(*SIGNALS) if none
109
+ signals=SIGNALS if signals.empty?
111
110
  signals.each do |signal|
112
111
  break if signal==''
113
112
  begin
@@ -117,11 +116,15 @@ module Such
117
116
  warn "Warning: no #{signal} signal for #{obj.class}"
118
117
  end
119
118
  end
120
- elsif not none
119
+ elsif !signals.empty?
121
120
  warn "Warning: No block given for #{signals.join(',')} on #{obj.class}."
122
121
  end
123
122
  end
124
123
 
124
+ # Given an Object not sub-classed as a Thing:
125
+ # obj = NotAThing.new
126
+ # One can still act on it like a Thing as follows:
127
+ # Thing.do_config(obj, *parameters, &block)
125
128
  def self.do_config(obj, *parameters, &block)
126
129
  container, arguments, methods, signals = Thing.do_parameters(parameters)
127
130
  Thing.do_methods(obj, methods, container)
@@ -129,6 +132,7 @@ module Such
129
132
  warn "Warning: arguments not used in do_config(#{obj.class}...)." if arguments.length > 0
130
133
  end
131
134
 
135
+ # The alternate sub-class constructor:
132
136
  def initialize(*parameters, &block)
133
137
  container, arguments, methods, signals = Thing.do_parameters(parameters)
134
138
  super(*arguments)
data/lib/such/things.rb CHANGED
@@ -1,19 +1,20 @@
1
1
  module Such
2
2
  module Things
3
- def self.list(superklass)
4
- ObjectSpace.each_object(Class).select{|klass| klass < superklass}
3
+ def self.list(super_class)
4
+ ObjectSpace.each_object(Class).select{_1 < super_class}
5
5
  end
6
6
 
7
- def self.subclass(klass)
8
- Such.subclass(klass.name.sub(/^.*::/,'').to_sym, klass, include: Such::Thing)
7
+ def self.subclass(sub_class)
8
+ Such.subclass(sub_class.name.sub(/^.*::/,'').to_sym, sub_class,
9
+ include: Such::Thing)
9
10
  end
10
11
 
11
- def self.in(superklass)
12
- Things.list(superklass).each do |klass|
12
+ def self.in(super_class)
13
+ Things.list(super_class).each do |sub_class|
13
14
  begin
14
- Things.subclass(klass)
15
+ Things.subclass(sub_class)
15
16
  rescue
16
- $stderr.puts "#{$!.class}:\t#{superklass}" if $VERBOSE
17
+ $stderr.puts "#{$!.class}:\t#{super_class}" if $VERBOSE
17
18
  end
18
19
  end
19
20
  end
data/lib/such.rb CHANGED
@@ -1,10 +1,11 @@
1
1
  module Such
2
- VERSION = '2.0.210201'
2
+ VERSION = '2.1.230106'
3
+ require 'such/such'
4
+ autoload :Convention, 'such/convention.rb'
5
+ autoload :Thing, 'such/thing.rb'
6
+ autoload :Things, 'such/things.rb'
7
+ autoload :Part, 'such/part.rb'
8
+ autoload :Parts, 'such/parts.rb'
3
9
  end
4
- require 'such/such'
5
- require 'such/thing'
6
- require 'such/things'
7
- require 'such/part'
8
- require 'such/parts'
9
10
  # Requires:
10
11
  #`ruby`
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: such
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.210201
4
+ version: 2.1.230106
5
5
  platform: ruby
6
6
  authors:
7
- - carlosjhr64
8
- autorequire:
7
+ - CarlosJHR64
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-01 00:00:00.000000000 Z
11
+ date: 2023-01-06 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |
14
14
  Wraps widgets with an alternate constructor
@@ -22,6 +22,7 @@ extra_rdoc_files: []
22
22
  files:
23
23
  - README.md
24
24
  - lib/such.rb
25
+ - lib/such/convention.rb
25
26
  - lib/such/part.rb
26
27
  - lib/such/parts.rb
27
28
  - lib/such/such.rb
@@ -31,7 +32,7 @@ homepage: https://github.com/carlosjhr64/such
31
32
  licenses:
32
33
  - MIT
33
34
  metadata: {}
34
- post_install_message:
35
+ post_install_message:
35
36
  rdoc_options: []
36
37
  require_paths:
37
38
  - lib
@@ -46,9 +47,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
46
47
  - !ruby/object:Gem::Version
47
48
  version: '0'
48
49
  requirements:
49
- - 'ruby: ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-linux]'
50
- rubygems_version: 3.2.3
51
- signing_key:
50
+ - 'ruby: ruby 3.2.0 (2022-12-25 revision a528908271) [aarch64-linux]'
51
+ rubygems_version: 3.4.2
52
+ signing_key:
52
53
  specification_version: 4
53
54
  summary: Wraps widgets with an alternate constructor which factors out the configuration
54
55
  and assembly procedures into metadata. Can be used to wrap any class with the alternate