acrylic 0.2.3 → 0.4.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: '0643134970d466fe2fe05ff4d844361c34316965ababe2347cf49da3d0f6d77f'
4
- data.tar.gz: b0b715cbf01c62313b5914b679e387e1170843f2d7fd98cec510567ab1ca4010
3
+ metadata.gz: 3c867a949c6d7b81cf0e358387cf9ee06bb2cb460901eb089492f589e5c1e31f
4
+ data.tar.gz: c66069736873cab0183f99cb2832c8339eabb4540af63b8b99208678eaa81cc9
5
5
  SHA512:
6
- metadata.gz: c5c35841c697d6ae533ee1545ba9b805e48199c79c87c462350237cdefe3aface8e32644b956ea0fdcee671916e9f5dd1d65ab4c335387fa41114c67fa1dbc3c
7
- data.tar.gz: ab74056949e7966f2d686b49a99eda09fbc8620831a8ccae985db1132ac548a45966456e77de5eabb2b27a8367f6d0b229ac004ba2d926d4bc3549f8e2ba3aba
6
+ metadata.gz: '08c812a7ab32c4672692ad5989fc04a32467e0bab0ec6a4174b3d54f0bfd85d011e0ffe822f52ea889366156469d62e4bd9d30147ef680082f3ae2bbd5a40734'
7
+ data.tar.gz: f4f0f3326cba037385f1618733ae41f40ed7bd1e80bea879c9a368d940faeabcf7a245fed7ff5bc4a350570d5982828dfd4b14c048e618f0427ea3f91bec67d6
data/lib/bits.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'ostruct'
2
+
1
3
  class Object
2
4
  def containerize
3
5
  if self.is_a? Array then self else [self].compact end
@@ -18,4 +20,29 @@ class Hash
18
20
  def self.from_keys keys, value = nil
19
21
  keys.map do |k| [k, value] end.to_h
20
22
  end
23
+
24
+ def self.from_values values
25
+ k = -1
26
+ values.map do |v|
27
+ k += 1
28
+ [k, v]
29
+ end.to_h
30
+ end
31
+
32
+ # recursively converts hash to ostruct.
33
+ def structize
34
+ OpenStruct.new (map do |k, v| [k, if v.is_a? Hash then v.structize else v end] end.to_h)
35
+ end
36
+
37
+ # recursively convert keys to symbols
38
+ def with_sym_keys
39
+ map do |k, v| [k.to_sym, if v.is_a? Hash then v.with_sym_keys else v end] end.to_h
40
+ end
41
+ end
42
+
43
+ class Array
44
+ # like sort by, but sorts entries with same index
45
+ def sort_by_stable &proc
46
+ Hash.from_values(self).sort_by do |k, v| [proc.call(v), k] end.to_h.values
47
+ end
21
48
  end
data/lib/cascade.rb CHANGED
@@ -5,17 +5,15 @@ module Acrylic
5
5
  ROUTES = []
6
6
 
7
7
  class Route
8
- # list of HTTP verbs the request will be matched against.
9
- attr_reader :verbs
10
-
11
8
  # list of path rules (wildcards or regexps)
12
9
  attr_reader :paths
10
+ attr_reader :priority
13
11
 
14
12
  def initialize args, handler
15
13
  @handler = handler
16
14
 
15
+ @priority = args[:priority] or 0 # defualt priority
17
16
  @paths = args[:path].containerize
18
- @verbs = (args[:verb] or :GET).containerize.map do |verb| verb.downcase.to_sym end
19
17
  end
20
18
 
21
19
  # transforms a rule from string (e.g. "/User/<id>") to wildcard
@@ -50,7 +48,7 @@ module Acrylic
50
48
 
51
49
  def match? req
52
50
  # match against paths
53
- (path_match? req.path) and (@verbs.include? req.request_method.downcase.to_sym )
51
+ (path_match? req.path)
54
52
  end
55
53
 
56
54
  def call req, *args
@@ -66,8 +64,10 @@ module Acrylic
66
64
  config = OpenStruct.new
67
65
 
68
66
  # loop through all the routes to find a final one
69
- Acrylic::ROUTES.each do |route|
67
+ # (and sort them by priority descending and index)
68
+ Acrylic::ROUTES.sort_by_stable do |route| route.priority end.each do |route|
70
69
  next unless route.match? req
70
+ puts route.priority
71
71
 
72
72
  res = route.call config, req, *(route.args_for_path req.path)
73
73
 
data/lib/validator.rb ADDED
@@ -0,0 +1,76 @@
1
+ module Acrylic
2
+
3
+ # a schema is a hash that validates another hash.
4
+ # values in the schema represent conditions to validate the object against.
5
+ # e.g.
6
+ # {
7
+ # email: [:email, [:length, (..32)]]
8
+ # username: [:not_null, [:length, (..32)]]
9
+ # password: [:not_null, [:length, (8..32)]]
10
+ # }
11
+ #
12
+ # string keys in the object are automatically converted to symbols.
13
+
14
+ module Validators
15
+ def email val
16
+ # shamelessly stolen from https://github.com/zombor/Validator/blob/master/lib/validation/rule/email.rb
17
+ email_address = begin
18
+ letter = 'a-zA-Z'
19
+ digit = '0-9'
20
+ atext = "[#{letter}#{digit}\!\#\$\%\&\'\*+\/\=\?\^\_\`\{\|\}\~\-]"
21
+ dot_atom_text = "#{atext}+([.]#{atext}*)+"
22
+ dot_atom = dot_atom_text
23
+ no_ws_ctl = '\x01-\x08\x11\x12\x14-\x1f\x7f'
24
+ qtext = "[^#{no_ws_ctl}\\x0d\\x22\\x5c]" # Non-whitespace, non-control character except for \ and "
25
+ text = '[\x01-\x09\x11\x12\x14-\x7f]'
26
+ quoted_pair = "(\\x5c#{text})"
27
+ qcontent = "(?:#{qtext}|#{quoted_pair})"
28
+ quoted_string = "[\"]#{qcontent}+[\"]"
29
+ atom = "#{atext}+"
30
+ word = "(?:#{atom}|#{quoted_string})"
31
+ obs_local_part = "#{word}([.]#{word})*"
32
+ local_part = "(?:#{dot_atom}|#{quoted_string}|#{obs_local_part})"
33
+ dtext = "[#{no_ws_ctl}\\x21-\\x5a\\x5e-\\x7e]"
34
+ dcontent = "(?:#{dtext}|#{quoted_pair})"
35
+ domain_literal = "\\[#{dcontent}+\\]"
36
+ obs_domain = "#{atom}([.]#{atom})+"
37
+ domain = "(?:#{dot_atom}|#{domain_literal}|#{obs_domain})"
38
+ addr_spec = "#{local_part}\@#{domain}"
39
+ pattern = /\A#{addr_spec}\z/u
40
+ end
41
+
42
+ !!email_address.match(val)
43
+ end
44
+
45
+ def not_null val; not val.nil? end
46
+ def length val, range; range.include? val.length end
47
+ def range val, range; range.include? val end
48
+ def regex val, expr; expr.match? val end
49
+ end
50
+
51
+ def valid? object, schema
52
+ object = object.with_sym_keys
53
+ schema.each do |key, conditions|
54
+ value = object[key]
55
+
56
+ # apply conditions
57
+ if conditions.is_a? Hash
58
+ return false unless value.is_a? Hash
59
+ return false unless valid? value, conditions
60
+ else
61
+ conditions = conditions.containerize
62
+
63
+ # check every condition (in order)
64
+ conditions.each do |condition|
65
+ condition = condition.containerize
66
+ opcode, *args = condition
67
+ if opcode == :default then value = args[0] if value.nil?
68
+ else return false unless Validators.instance_method(opcode).bind(nil).call value, *args
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ return true
75
+ end
76
+ end
data/lib/version.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  module Acrylic
2
2
  class Version
3
3
  MAJOR = 0
4
- MINOR = 2
5
- HOTFIX = 3
4
+ MINOR = 4
5
+ HOTFIX = 0
6
6
 
7
7
  def self.semver
8
8
  "#{MAJOR}.#{MINOR}.#{HOTFIX}"
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acrylic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - fmixolydian
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-01-01 00:00:00.000000000 Z
10
+ date: 2026-01-04 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rack
@@ -66,6 +66,7 @@ files:
66
66
  - lib/cascade.rb
67
67
  - lib/cascade/errors.rb
68
68
  - lib/kronos.rb
69
+ - lib/validator.rb
69
70
  - lib/version.rb
70
71
  homepage: https://codeberg.org/fmixolydian/acrylic
71
72
  licenses: