mayak 0.2.0 → 0.2.2

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: 7c803fe79f01fbe1d57d090db09b47e5e8500656819f61951e120fd10860680e
4
- data.tar.gz: 8dcaeaa4cbf92d629113c7faedaa1048dad5a69aaca38e82fbadd8609631be3b
3
+ metadata.gz: b4924104fc85c9c38df43b25f1902b6c58e3310014229f7a2c8ad728c3af497f
4
+ data.tar.gz: 249044e065aaa1617531d158bf3a7e2a2d100189550c94f5423501297e60b8e5
5
5
  SHA512:
6
- metadata.gz: 144fb12c3b37c4cd8f8abdcca91042178647273ee26f8abc23bf3f83373ad5e04affda9aa1a58331fc619f0c362156b57f5b6d5b66bde15bfd5b1c5b966ef042
7
- data.tar.gz: e50fe76a28b4591a0ee5b3de40da4b88bff7a05303d7673e00d9873b6abd41a6d6b94d0367660d61bd2777e2d3871f399a83b9f3fbcb1ad9bbaa97b868021184
6
+ metadata.gz: eb3bbe732669a8a56af42fda964d789baacdabfd225ca5f681cff02e6df26ed23f1c70a2cf001dfe4f2b66e66667e06331b5be7659a57fc6d2b0e52a994f1841
7
+ data.tar.gz: b03e54bfc4cf520db93e38ea02cadd8f6bd7e3cf81eb5da39c71545013e4d9005fbcc70c7778da35be2ef4bbba94ed9f883298998ce33b8240c9eacad2353d7e
data/README.md CHANGED
@@ -29,61 +29,14 @@ require "mayak"
29
29
 
30
30
  Mayak consists from separate classes and interfaces as well as separate modules for specific domains.
31
31
 
32
- #### Caching
33
-
34
- [Documentation](./lib/mayak/caching/README.md)
35
-
36
- #### Monads
37
-
38
- [Documentation](./lib/mayak/monads/README.md)
39
-
40
- #### HTTP
41
-
42
- [Documentation](./lib/mayak/http/README.md)
43
-
44
- #### Lazy
45
-
46
- [Documentation](./lib/mayak/lazy/README.md)
32
+ * [Caching](./docs/caching.md)
33
+ * [Monads](./docs/monads.md)
34
+ * [HTTP](./docs/http.md)
35
+ * [Lazy](./docs/lazy.md)
36
+ * [Functions](./docs/function.md)
47
37
 
48
38
  #### Miscellaneous
49
39
 
50
- ##### Function
51
- In some situations Sorbet can not infer a type of proc passed:
52
-
53
- ```ruby
54
- sig {
55
- type_parameters(:A)
56
- .params(blk: T.proc.params(arg0: T.type_parameter(:A)).returns(T.type_parameter(:A)))
57
- .returns(T.proc.params(arg0: T.type_parameter(:A)).returns(T.type_parameter(:A)))
58
- }
59
- def proc_identity(&blk)
60
- blk
61
- end
62
-
63
- T.reveal_type(proc_identity { |a| 10 })
64
- # This code is unreachable https://srb.help/7006
65
- # proc_identity { |a| 10 }
66
- ```
67
-
68
- `Mayak::Fuction` allows explicitly define input and output types to help sorbet infer types:
69
-
70
- ```ruby
71
- sig {
72
- type_parameters(:A)
73
- .params(
74
- fn: Mayak::Function[T.type_parameter(:A), T.type_parameter(:A)])
75
- .returns(Mayak::Function[T.type_parameter(:A), T.type_parameter(:A)])
76
- }
77
- def fn_identity(fn)
78
- fn
79
- end
80
-
81
- T.reveal_type(
82
- fn_identity(Mayak::Function[Integer, Integer].new { |a| a })
83
- )
84
- # Revealed type: Mayak::Function[Integer, Integer]
85
- ```
86
-
87
40
  ##### JSON
88
41
 
89
42
  `JSON` module provides a type alias to encode JSON type:
@@ -0,0 +1,20 @@
1
+ # typed: true
2
+
3
+
4
+ module Mayak
5
+ class JsonCodec::FromHashSerializable
6
+ extend T::Sig
7
+ extend T::Generic
8
+
9
+ include ::Mayak::Codec
10
+
11
+ Entity = type_member {{ upper: ::Mayak::HashSerializable }}
12
+ Protocol = type_member {{ fixed: String }}
13
+
14
+ sig { override.params(entity: Entity).returns(Protocol) }
15
+ def encode(entity); end
16
+
17
+ sig { override.params(response: Protocol).returns(::Mayak::Monads::Try[Entity]) }
18
+ def decode(response); end
19
+ end
20
+ end
data/lib/mayak/encoder.rb CHANGED
@@ -26,7 +26,6 @@ module Mayak
26
26
  blk.call(encode(entity))
27
27
  end
28
28
  end
29
-
30
29
  class Implementation
31
30
  extend T::Sig
32
31
  extend T::Generic
@@ -34,8 +33,8 @@ module Mayak
34
33
 
35
34
  include ::Mayak::Encoder
36
35
 
37
- In = type_member
38
- Out = type_member
36
+ In = type_member
37
+ Out = type_member
39
38
 
40
39
  sig { params(function: T.proc.params(in: In).returns(Out)).void }
41
40
  def initialize(&function)
@@ -0,0 +1,38 @@
1
+ # typed: ignore
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "../monads/try"
5
+ require "sorbet-coerce"
6
+
7
+ module Mayak
8
+ module JsonCodec
9
+ class FromHashSerializable
10
+ include ::Mayak::Monads::Try::Mixin
11
+
12
+ include ::Mayak::Codec
13
+
14
+ def initialize(type)
15
+ @type = type
16
+ end
17
+
18
+ def self.[](type)
19
+ ::Mayak::JsonCodec::FromHashSerializable.new(type)
20
+ end
21
+
22
+ def new
23
+ self
24
+ end
25
+
26
+ def encode(entity)
27
+ JSON.dump(entity.serialize)
28
+ end
29
+
30
+ def decode(response)
31
+ Try do
32
+ parsed = JSON.parse(response)
33
+ ::TypeCoerce::Converter.new(@type).from(parsed)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,29 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Mayak
5
+ module JsonCodec
6
+ extend T::Sig
7
+ extend T::Generic
8
+ extend T::Helpers
9
+
10
+ include ::Mayak::Codec
11
+
12
+ abstract!
13
+
14
+ Entity = type_member
15
+ Protocol = type_member {{ fixed: String }}
16
+
17
+ sig { abstract.params(entity: Entity).returns(Protocol) }
18
+ def encode(entity)
19
+ end
20
+
21
+ sig {
22
+ abstract
23
+ .params(response: Protocol)
24
+ .returns(Mayak::Monads::Try[Entity])
25
+ }
26
+ def decode(response)
27
+ end
28
+ end
29
+ end
data/lib/mayak.rb CHANGED
@@ -15,9 +15,12 @@ require_relative 'mayak/version'
15
15
  require_relative 'mayak/weak_ref'
16
16
  require_relative 'mayak/decoder'
17
17
  require_relative 'mayak/encoder'
18
+ require_relative 'mayak/codec'
18
19
  require_relative 'mayak/hash_serializable'
19
20
  require_relative 'mayak/lazy'
20
21
 
22
+ require_relative 'mayak/json_codec/from_hash_serializable'
23
+
21
24
  require_relative 'mayak/caching/unbounded_cache'
22
25
  require_relative 'mayak/caching/lru_cache'
23
26
 
@@ -30,7 +33,6 @@ require_relative 'mayak/http/request'
30
33
  require_relative 'mayak/http/response'
31
34
  require_relative 'mayak/http/verb'
32
35
  require_relative 'mayak/http/client'
33
-
34
36
  require_relative 'mayak/monads/maybe'
35
37
  require_relative 'mayak/monads/result'
36
38
  require_relative 'mayak/monads/try'
data/mayak.gemspec CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "mayak"
7
- spec.version = "0.2.0"
7
+ spec.version = "0.2.2"
8
8
  spec.summary = "Set of fully typed utility classes and interfaces integrated with Sorbet."
9
9
  spec.description = spec.summary
10
10
  spec.authors = ["Daniil Bober"]
@@ -15,6 +15,7 @@ Gem::Specification.new do |spec|
15
15
 
16
16
  spec.add_dependency 'sorbet-runtime'
17
17
  spec.add_dependency 'sorbet'
18
+ spec.add_dependency 'sorbet-coerce'
18
19
 
19
20
  spec.add_development_dependency "bundler"
20
21
  spec.add_development_dependency "rspec"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mayak
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniil Bober
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-07-07 00:00:00.000000000 Z
11
+ date: 2025-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sorbet-runtime
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: sorbet-coerce
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: bundler
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -88,9 +102,9 @@ extra_rdoc_files: []
88
102
  files:
89
103
  - LICENSE
90
104
  - README.md
105
+ - lib/bundled_rbi/mayak.rbi
91
106
  - lib/mayak.rb
92
107
  - lib/mayak/cache.rb
93
- - lib/mayak/caching/README.md
94
108
  - lib/mayak/caching/lru_cache.rb
95
109
  - lib/mayak/caching/unbounded_cache.rb
96
110
  - lib/mayak/codec.rb
@@ -111,7 +125,6 @@ files:
111
125
  - lib/mayak/failable_function.rb
112
126
  - lib/mayak/function.rb
113
127
  - lib/mayak/hash_serializable.rb
114
- - lib/mayak/http/README.md
115
128
  - lib/mayak/http/client.rb
116
129
  - lib/mayak/http/decoder.rb
117
130
  - lib/mayak/http/encoder.rb
@@ -119,10 +132,9 @@ files:
119
132
  - lib/mayak/http/response.rb
120
133
  - lib/mayak/http/verb.rb
121
134
  - lib/mayak/json.rb
122
- - lib/mayak/json/encoder.rb
135
+ - lib/mayak/json_codec.rb
136
+ - lib/mayak/json_codec/from_hash_serializable.rb
123
137
  - lib/mayak/lazy.rb
124
- - lib/mayak/lazy/README.md
125
- - lib/mayak/monads/README.md
126
138
  - lib/mayak/monads/maybe.rb
127
139
  - lib/mayak/monads/result.rb
128
140
  - lib/mayak/monads/try.rb
@@ -1,100 +0,0 @@
1
- # Caching
2
-
3
- Caching modules constist from `Mayak::Cache` and several implementations in `Mayak::Caching` module. `Mayak::Caching` provides in-memory caches using regular ruby hashes: an unbounded cache and a cache using LRU eviction policy.
4
-
5
- Usage of unbounded cache:
6
- ```ruby
7
- unbounded_cache = Mayak::Caching::UnboundedCache[String, Integer].new
8
- unbounded_cache.write("foo", 10)
9
- unbounded_cache.write("bar", 20)
10
-
11
- unbounded_cache.read("foo") # 10
12
- unbounded_cache.read("bar") # 20
13
- unbounded_cache.read("baz") # nil
14
-
15
- unbounded_cache.delete("bar")
16
- unbounded_cache.read("bar") # nil
17
-
18
- unbounded_cache.fetch("foo") { 100 } # 10
19
- unbounded_cache.fetch("bar") { 100 } # 100
20
- unbounded_cache.fetch("bar") { 200 } # 100
21
-
22
- unbounded_cache.clear # 100
23
- unbounded_cache.read("foo") # nil
24
- unbounded_cache.read("bar") # nil
25
- ```
26
-
27
- LRU cache has limited size: when the cache is full and a new element is added, some element is evicted using least recently used policy:
28
-
29
- ```ruby
30
- lru_cache = Mayak::Caching::LRUCache[String, Integer].new(max_size: 3)
31
-
32
- lru_cache.write("key1", 1)
33
- lru_cache.write("key2", 2)
34
- lru_cache.write("key3", 3)
35
-
36
- lru_cache.read("key1") # 1
37
- lru_cache.read("key2") # 2
38
- lru_cache.read("key3") # 3
39
-
40
- lru_cache.write("key4", 4)
41
- lru_cache.read("key4") # 4
42
- lru_cache.read("key1") # nil
43
- ```
44
-
45
- You can implement `Mayak::Cache` interface using a different store (for example default Rails cache) and use different implementations interchangeably:
46
-
47
- ```ruby
48
- class RailsCache < T::Struct
49
- extend T::Sig
50
- extend T::Generic
51
- extend T::Helpers
52
-
53
- include Mayak::Cache
54
-
55
- Key = type_member
56
- Value = type_member
57
-
58
- const :converter, T.proc.params(value: T.untyped).returns(Value)
59
-
60
- sig { override.params(key: Key).returns(T.nilable(Value)) }
61
- def read(key)
62
- converter.call(Rails.cache.read(key))
63
- end
64
-
65
- sig { override.params(key: Key, value: Value).void }
66
- def write(key, value)
67
- Rails.cache.write(key, value)
68
- end
69
-
70
- sig { override.params(key: Key, blk: T.proc.returns(Value)).returns(Value) }
71
- def fetch(key, &blk)
72
- converter.call(Rails.cache.fetch(key, &blk))
73
- end
74
-
75
- sig { override.void }
76
- def clear
77
- Rails.cache.clear
78
- end
79
-
80
- sig { override.params(key: Key).void }
81
- def delete(key)
82
- Rails.cache.delete(key)
83
- end
84
- end
85
-
86
- class Service < T::Struct
87
- extend T::Sig
88
-
89
- const :cache, Mayak::Cache[String, String]
90
- end
91
-
92
- in_memory = Service.new(
93
- cache: Mayak::Caching::UnboundedCache[String, String].new
94
- )
95
- rails_cache = Service.new(
96
- cache: RailsCache[String, String].new(
97
- converter: -> (value) { value.to_s }
98
- )
99
- )
100
- ```
@@ -1,105 +0,0 @@
1
- # Http
2
-
3
- This module contains abstraction for HTTP interactions. It provides data classes that models HTTP requests and response as well interfaces for http client and codecs.
4
-
5
- #### Verb
6
-
7
- Enumaration that encodes an HTTP verb.
8
-
9
- ```ruby
10
- get_verb = Mayak::Http::Verb::Get
11
- post_verb = Mayak::Http::Verb::Post
12
- head_verb = Mayak::Http::Verb::Head
13
- put_verb = Mayak::Http::Verb::Put
14
- patch_verb = Mayak::Http::Verb::Patch
15
- delete_verb = Mayak::Http::Verb::Delete
16
- connect_verb = Mayak::Http::Verb::Connect
17
- options_verb = Mayak::Http::Verb::Options
18
- trace_verb = Mayak::Http::Verb::Trace
19
- ```
20
-
21
- #### Request
22
-
23
- `Mayak::Http::Request` is a datastructure that encodes an HTTP request.
24
- ```ruby
25
- # to build an HTTP request verb and URI should be provided, as well as optional headers hash and body
26
- request = Mayak::Http::Request.new(
27
- verb: Mayak::Http::Verb::Put,
28
- url: URI.parse("https://www.foobar.com/users/update"),
29
- headers: { "content-type" => "application/json" },
30
- body: """{ id: 100, name: "Daniil" })"""
31
- )
32
-
33
- # to build request helper constructor methods can be used
34
- get_request = Mayak::Http::Request.get(url: URI.parse("https://www.foobar.com"))
35
- ```
36
-
37
- #### Response
38
-
39
- `Mayak::Http::Response` is a datastructure that encodes an HTTP request. It contains status, and optional headers and body:
40
-
41
- ```ruby
42
- response = Mayak::Http::Response.new(
43
- status: 200
44
- headers: { "content-type" => "application/json" },
45
- body: """{ id: 100, name: "Daniil" }"""
46
- )
47
- ```
48
-
49
- #### Client
50
-
51
- Interface that encodes an HTTP client. The interface is very simple and consists from one method that receives a request and returns a `Try` monad containg response:
52
- ```ruby
53
- module Mayak
54
- module Http
55
- module Client
56
- extend T::Sig
57
- extend T::Generic
58
-
59
- interface!
60
-
61
- sig { abstract.params(request: Http::Request).returns(Mayak::Monads::Try[Mayak::Http::Response]) }
62
- def send_request(request)
63
- end
64
- end
65
- end
66
- end
67
- ```
68
-
69
- You can implement this interface using a specific library:
70
-
71
- ```ruby
72
- class FaradayClient
73
- extend T::Sig
74
-
75
- include Mayak::Http::Client
76
-
77
- include Mayak::Monads::Try::Mixin
78
-
79
- sig { params(config_blk: T.nilable(T.proc.params(connection: Faraday::Connection).void)).void }
80
- def initialize(&config_blk)
81
- @faraday_instance = T.let(
82
- config_blk.nil? ? Faraday.new : Faraday.new(&@config_blk),
83
- Faraday
84
- )
85
- end
86
-
87
- sig { override.params(request: Mayak::Http::Request).returns(Mayak::Monads::Try[Mayak::Http::Response]) }
88
- def send_request(request)
89
- Try do
90
- faraday_response = @faraday_instance.run_request(
91
- verb.serialize.downcase.to_sym,
92
- request.url,
93
- request.body,
94
- request.headers
95
- )
96
-
97
- Mayak::Http::Response.new(
98
- status: T.must(faraday_response.status.to_i),
99
- headers: faraday_response.headers || {},
100
- body: faraday_response.body || ""
101
- )
102
- end
103
- end
104
- end
105
- ```
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
- # typed: strict
3
-
4
- require "json"
5
-
6
- module Mayak
7
- module Json
8
- module Encoder
9
- extend T::Sig
10
- extend T::Generic
11
- extend T::Helpers
12
-
13
- abstract!
14
-
15
- include ::Mayak::Encoder
16
-
17
- In = type_member
18
- Out = type_member {{ fixed: ::Mayak::Json::JsonType }}
19
- end
20
- end
21
- end