ruby-object-framework 1.0.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 +7 -0
- data/API.md +78 -0
- data/README.md +250 -0
- data/THIRD_PARTY_NOTICES.md +45 -0
- data/examples/guides/01_plain_use_case.rb +13 -0
- data/examples/guides/02_composed_application.rb +25 -0
- data/examples/guides/03_order_domain.rb +14 -0
- data/examples/guides/04_scoped_resources.rb +38 -0
- data/examples/guides/05_mapping.rb +39 -0
- data/examples/guides/06_associations.rb +49 -0
- data/examples/guides/07_http.rb +17 -0
- data/examples/guides/08_errors.rb +20 -0
- data/examples/guides/09_sqlite.rb +38 -0
- data/examples/guides/10_grpc.rb +26 -0
- data/examples/guides/11_ractor.rb +15 -0
- data/examples/guides/12_box.rb +11 -0
- data/examples/guides/13_testing.rb +24 -0
- data/examples/guides/manifest.yml +62 -0
- data/examples/orders/application.rb +51 -0
- data/examples/orders/contracts.rb +19 -0
- data/examples/orders/domain.rb +35 -0
- data/examples/orders/export_proto.rb +5 -0
- data/examples/orders/grpc_client.py +24 -0
- data/examples/orders/grpc_server.rb +23 -0
- data/examples/orders/server.rb +18 -0
- data/lib/object_framework/application.rb +136 -0
- data/lib/object_framework/capabilities.rb +59 -0
- data/lib/object_framework/errors.rb +85 -0
- data/lib/object_framework/execution.rb +184 -0
- data/lib/object_framework/grpc/messages.rb +30 -0
- data/lib/object_framework/grpc/server.rb +264 -0
- data/lib/object_framework/grpc/service.rb +55 -0
- data/lib/object_framework/http/io.rb +127 -0
- data/lib/object_framework/http/presentation.rb +55 -0
- data/lib/object_framework/http/protocol.rb +209 -0
- data/lib/object_framework/http/router.rb +80 -0
- data/lib/object_framework/http/server.rb +279 -0
- data/lib/object_framework/http2/connection.rb +399 -0
- data/lib/object_framework/http2/frame.rb +21 -0
- data/lib/object_framework/http2/hpack.rb +206 -0
- data/lib/object_framework/http2/hpack_tables.rb +333 -0
- data/lib/object_framework/http2/inbound.rb +75 -0
- data/lib/object_framework/memory/storage.rb +97 -0
- data/lib/object_framework/persistence/mapping.rb +150 -0
- data/lib/object_framework/persistence/query.rb +97 -0
- data/lib/object_framework/persistence/session.rb +173 -0
- data/lib/object_framework/persistence/transaction.rb +54 -0
- data/lib/object_framework/protobuf.rb +268 -0
- data/lib/object_framework/sqlite/compiler.rb +77 -0
- data/lib/object_framework/sqlite/schema.rb +95 -0
- data/lib/object_framework/sqlite/storage.rb +220 -0
- data/lib/object_framework/sqlite.rb +6 -0
- data/lib/object_framework/version.rb +5 -0
- data/lib/object_framework.rb +31 -0
- metadata +105 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ObjectFramework
|
|
4
|
+
module SQLite
|
|
5
|
+
ForeignKey = Data.define(:table, :column, :target)
|
|
6
|
+
Migration = Data.define(:version, :actions)
|
|
7
|
+
|
|
8
|
+
class Schema
|
|
9
|
+
TYPES = { string: "TEXT", integer: "INTEGER", float: "REAL", boolean: "INTEGER", blob: "BLOB" }.freeze
|
|
10
|
+
attr_reader :tables, :foreign_keys, :migrations
|
|
11
|
+
|
|
12
|
+
def self.from_mappings(mappings)
|
|
13
|
+
mappings.validate!
|
|
14
|
+
keys = mappings.flat_map do |mapping|
|
|
15
|
+
mapping.associations.select { |item| item.kind == :belongs_to }.map do |association|
|
|
16
|
+
ForeignKey.new(table: mapping.table, column: association.foreign_key, target: mappings.fetch(association.target).table)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
new(tables: mappings.to_h { |mapping| [mapping.table, mapping.schema] }, foreign_keys: keys)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def initialize(tables:, foreign_keys: [])
|
|
23
|
+
@tables = tables.to_h do |name, columns|
|
|
24
|
+
fields = columns.to_h { |column, type| [identifier(column), validate_type(type)] }
|
|
25
|
+
raise ConfigurationError, "SQLite tables require a string id" unless fields[:id] == :string
|
|
26
|
+
[identifier(name), fields]
|
|
27
|
+
end
|
|
28
|
+
@foreign_keys = foreign_keys.dup.freeze
|
|
29
|
+
@initial_tables = @tables.transform_values { |columns| columns.dup.freeze }.freeze
|
|
30
|
+
@migrations = [Migration.new(version: 1, actions: [].freeze)]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def migration(version, &declaration)
|
|
34
|
+
raise ConfigurationError, "Schema is finalized" if frozen?
|
|
35
|
+
raise ConfigurationError, "Migration versions must be consecutive" unless version == @migrations.last.version + 1
|
|
36
|
+
editor = Editor.new(self)
|
|
37
|
+
editor.instance_eval(&declaration)
|
|
38
|
+
@migrations << Migration.new(version:, actions: editor.actions.each(&:freeze).freeze)
|
|
39
|
+
self
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def version; @migrations.last.version; end
|
|
43
|
+
|
|
44
|
+
def table(name)
|
|
45
|
+
@tables.fetch(identifier(name)) { raise ConfigurationError, "Unregistered SQLite table" }
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def type(table_name, column)
|
|
49
|
+
table(table_name).fetch(identifier(column)) { raise ConfigurationError, "Unregistered SQLite column" }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def quote(name); '"' + identifier(name).to_s + '"'; end
|
|
53
|
+
def identifier(name); Persistence::Query.identifier(name); end
|
|
54
|
+
|
|
55
|
+
def validate_type(type)
|
|
56
|
+
raise ConfigurationError, "Unknown SQLite field type" unless TYPES.key?(type)
|
|
57
|
+
type
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def finalize!
|
|
61
|
+
return self if frozen?
|
|
62
|
+
foreign_keys.each { |key| type(key.table, key.column); type(key.target, :id) }
|
|
63
|
+
@tables.each_value(&:freeze)
|
|
64
|
+
@tables.freeze
|
|
65
|
+
@migrations.freeze
|
|
66
|
+
freeze
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def create_statements
|
|
70
|
+
@initial_tables.map do |name, columns|
|
|
71
|
+
fields = columns.map do |column, type|
|
|
72
|
+
"#{quote(column)} #{TYPES.fetch(type)}#{column == :id ? ' PRIMARY KEY NOT NULL' : ''}"
|
|
73
|
+
end
|
|
74
|
+
foreign_keys.select { |key| key.table == name }.each do |key|
|
|
75
|
+
fields << "FOREIGN KEY (#{quote(key.column)}) REFERENCES #{quote(key.target)} (\"id\") DEFERRABLE INITIALLY DEFERRED"
|
|
76
|
+
end
|
|
77
|
+
"CREATE TABLE #{quote(name)} (#{fields.join(', ')}) STRICT"
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
class Editor
|
|
82
|
+
attr_reader :actions
|
|
83
|
+
def initialize(schema); @schema, @actions = schema, []; end
|
|
84
|
+
|
|
85
|
+
def add_column(table, column, type: :string)
|
|
86
|
+
table, column = @schema.identifier(table), @schema.identifier(column)
|
|
87
|
+
fields = @schema.table(table)
|
|
88
|
+
raise ConfigurationError, "Column already exists" if fields.key?(column)
|
|
89
|
+
fields[column] = @schema.validate_type(type)
|
|
90
|
+
@actions << "ALTER TABLE #{@schema.quote(table)} ADD COLUMN #{@schema.quote(column)} #{TYPES.fetch(type)}"
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ObjectFramework
|
|
4
|
+
module SQLite
|
|
5
|
+
module ErrorTranslation
|
|
6
|
+
def self.raise_translated(error)
|
|
7
|
+
code = error.code
|
|
8
|
+
type = case code
|
|
9
|
+
when 1555, 2067 then Duplicate
|
|
10
|
+
when 517 then Conflict
|
|
11
|
+
when 787, 1299, 275, 3091 then InvalidInput
|
|
12
|
+
else
|
|
13
|
+
case code & 255
|
|
14
|
+
when 5, 6, 10, 13, 14 then Unavailable
|
|
15
|
+
when 19, 20, 18 then InvalidInput
|
|
16
|
+
else nil
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
raise(type.new("SQLite operation failed"), cause: error) if type
|
|
20
|
+
raise error
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class Storage
|
|
25
|
+
attr_reader :schema_version
|
|
26
|
+
|
|
27
|
+
def initialize(path:, schema:, lock_timeout: 1)
|
|
28
|
+
raise ConfigurationError, "SQLite requires a database file path" if path.to_s.empty? || path.to_s == ":memory:"
|
|
29
|
+
raise ConfigurationError, "Lock timeout must be positive" unless lock_timeout.is_a?(Numeric) && lock_timeout.positive?
|
|
30
|
+
@path, @schema, @lock_timeout = File.expand_path(path), schema.finalize!, lock_timeout
|
|
31
|
+
@mutex, @connections, @closed = Mutex.new, 0, false
|
|
32
|
+
migrate
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def open_connection_count; @mutex.synchronize { @connections }; end
|
|
36
|
+
|
|
37
|
+
def begin_transaction(mode:)
|
|
38
|
+
begin_transaction_for(mode:, context: ExecutionContext.new)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def begin_transaction_for(mode:, context:)
|
|
42
|
+
@mutex.synchronize { raise Unavailable, "Storage is closed" if @closed }
|
|
43
|
+
context.cancellation.check!
|
|
44
|
+
database = connect(cancellation: context.cancellation)
|
|
45
|
+
Transaction.new(database:, schema: @schema, mode:, cancellation: context.cancellation,
|
|
46
|
+
closed: -> { disconnected })
|
|
47
|
+
rescue Exception
|
|
48
|
+
if database && !database.closed?
|
|
49
|
+
database.close
|
|
50
|
+
disconnected
|
|
51
|
+
end
|
|
52
|
+
raise
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def close
|
|
56
|
+
@mutex.synchronize { @closed = true }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def connect(cancellation: Cancellation.new)
|
|
62
|
+
database = ::SQLite3::Database.new(@path, results_as_hash: true)
|
|
63
|
+
@mutex.synchronize { @connections += 1 }
|
|
64
|
+
database.extended_result_codes = true
|
|
65
|
+
lock_started = nil
|
|
66
|
+
database.busy_handler do |count|
|
|
67
|
+
cancellation.check!
|
|
68
|
+
lock_started = monotonic if count.zero? || lock_started.nil?
|
|
69
|
+
remaining = @lock_timeout - (monotonic - lock_started)
|
|
70
|
+
if remaining.positive?
|
|
71
|
+
sleep [remaining, 0.005].min
|
|
72
|
+
true
|
|
73
|
+
else
|
|
74
|
+
false
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
database.execute("PRAGMA foreign_keys = ON")
|
|
78
|
+
database.execute("PRAGMA synchronous = FULL")
|
|
79
|
+
database
|
|
80
|
+
rescue Exception => error
|
|
81
|
+
if database
|
|
82
|
+
database.close unless database.closed?
|
|
83
|
+
disconnected
|
|
84
|
+
end
|
|
85
|
+
ErrorTranslation.raise_translated(error) if error.is_a?(::SQLite3::Exception)
|
|
86
|
+
raise
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def disconnected
|
|
90
|
+
@mutex.synchronize { @connections -= 1 }
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def migrate
|
|
94
|
+
database = connect
|
|
95
|
+
database.execute("PRAGMA journal_mode = DELETE")
|
|
96
|
+
database.execute("BEGIN IMMEDIATE")
|
|
97
|
+
current = database.get_first_value("PRAGMA user_version")
|
|
98
|
+
raise ConfigurationError, "Database schema is newer than the application" if current > @schema.version
|
|
99
|
+
@schema.migrations.each do |migration|
|
|
100
|
+
next if migration.version <= current
|
|
101
|
+
statements = migration.version == 1 ? @schema.create_statements : migration.actions
|
|
102
|
+
statements.each { |statement| database.execute(statement) }
|
|
103
|
+
database.execute("PRAGMA user_version = #{migration.version}")
|
|
104
|
+
end
|
|
105
|
+
validate_schema(database)
|
|
106
|
+
database.execute("COMMIT")
|
|
107
|
+
@schema_version = @schema.version
|
|
108
|
+
rescue ::SQLite3::Exception => error
|
|
109
|
+
ErrorTranslation.raise_translated(error)
|
|
110
|
+
ensure
|
|
111
|
+
if database
|
|
112
|
+
database.close
|
|
113
|
+
disconnected
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def monotonic
|
|
118
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def validate_schema(database)
|
|
122
|
+
@schema.tables.each do |name, columns|
|
|
123
|
+
actual = database.execute("PRAGMA table_info(#{@schema.quote(name)})").to_h { |row| [row.fetch("name"), row.fetch("type")] }
|
|
124
|
+
expected = columns.to_h { |column, type| [column.to_s, Schema::TYPES.fetch(type)] }
|
|
125
|
+
raise ConfigurationError, "SQLite schema does not match its declared version" unless actual == expected
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
class Transaction < Persistence::Transaction
|
|
131
|
+
def initialize(database:, schema:, mode:, cancellation:, closed:)
|
|
132
|
+
super(mode:)
|
|
133
|
+
@database, @schema, @cancellation, @closed_callback = database, schema, cancellation, closed
|
|
134
|
+
@compiler = Compiler.new(schema:)
|
|
135
|
+
execute(mode == :write ? "BEGIN IMMEDIATE" : "BEGIN DEFERRED")
|
|
136
|
+
@database.execute("PRAGMA query_only = ON") if mode == :read
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def configuration
|
|
140
|
+
active!
|
|
141
|
+
%i[foreign_keys journal_mode synchronous].to_h { |name| [name, @database.get_first_value("PRAGMA #{name}")] }
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def find(table, id)
|
|
145
|
+
query(Persistence::Query.new(table:).where(id:).limit(1)).first
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def query(query)
|
|
149
|
+
active!
|
|
150
|
+
sql, bindings = @compiler.query(query)
|
|
151
|
+
execute(sql, bindings).map { |row| @compiler.decode(query.table, row) }
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def insert(table, row)
|
|
155
|
+
writable!
|
|
156
|
+
value = row_value(row)
|
|
157
|
+
@schema.table(table)
|
|
158
|
+
columns = value.keys
|
|
159
|
+
bindings = columns.map { |column| @compiler.encode(table, column, value[column]) }
|
|
160
|
+
execute("INSERT INTO #{@schema.quote(table)} (#{columns.map { |column| @schema.quote(column) }.join(', ')}) VALUES (#{(['?'] * columns.size).join(', ')})", bindings)
|
|
161
|
+
value[:id]
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def update(table, id, row)
|
|
165
|
+
writable!
|
|
166
|
+
value = row_value(row, id:)
|
|
167
|
+
@schema.table(table)
|
|
168
|
+
columns = @schema.table(table).keys - [:id]
|
|
169
|
+
if columns.empty?
|
|
170
|
+
raise NotFound, "Unknown identity" unless find(table, id)
|
|
171
|
+
return
|
|
172
|
+
end
|
|
173
|
+
values = columns.map { |column| @compiler.encode(table, column, value[column]) }
|
|
174
|
+
sql = "UPDATE #{@schema.quote(table)} SET #{columns.map { |column| "#{@schema.quote(column)} = ?" }.join(', ')} WHERE \"id\" = ?"
|
|
175
|
+
execute(sql, values + [id])
|
|
176
|
+
raise NotFound, "Unknown identity" if @database.changes.zero?
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def delete(table, id)
|
|
180
|
+
writable!
|
|
181
|
+
@schema.table(table)
|
|
182
|
+
execute("DELETE FROM #{@schema.quote(table)} WHERE \"id\" = ?", [id])
|
|
183
|
+
raise NotFound, "Unknown identity" if @database.changes.zero?
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def commit
|
|
187
|
+
active!
|
|
188
|
+
begin
|
|
189
|
+
execute("COMMIT")
|
|
190
|
+
@state = :committed
|
|
191
|
+
rescue StandardError
|
|
192
|
+
@state = :indeterminate unless @database.transaction_active?
|
|
193
|
+
raise
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
private
|
|
198
|
+
|
|
199
|
+
def execute(sql, bindings = [])
|
|
200
|
+
@cancellation.check!
|
|
201
|
+
@database.execute(sql, bindings)
|
|
202
|
+
rescue ::SQLite3::Exception => error
|
|
203
|
+
ErrorTranslation.raise_translated(error)
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def rollback_storage
|
|
207
|
+
# Cleanup must remain possible after deadline expiry or cancellation.
|
|
208
|
+
@database.execute("ROLLBACK")
|
|
209
|
+
rescue ::SQLite3::Exception => error
|
|
210
|
+
ErrorTranslation.raise_translated(error)
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def close_storage
|
|
214
|
+
@database.close
|
|
215
|
+
ensure
|
|
216
|
+
@closed_callback.call
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "securerandom"
|
|
4
|
+
require "thread"
|
|
5
|
+
require_relative "object_framework/version"
|
|
6
|
+
require_relative "object_framework/errors"
|
|
7
|
+
require_relative "object_framework/execution"
|
|
8
|
+
require_relative "object_framework/application"
|
|
9
|
+
require_relative "object_framework/persistence/query"
|
|
10
|
+
require_relative "object_framework/persistence/transaction"
|
|
11
|
+
require_relative "object_framework/persistence/mapping"
|
|
12
|
+
require_relative "object_framework/persistence/session"
|
|
13
|
+
require_relative "object_framework/memory/storage"
|
|
14
|
+
require_relative "object_framework/http/protocol"
|
|
15
|
+
require_relative "object_framework/http/router"
|
|
16
|
+
require_relative "object_framework/http/presentation"
|
|
17
|
+
require_relative "object_framework/http/io"
|
|
18
|
+
require_relative "object_framework/http/server"
|
|
19
|
+
require_relative "object_framework/protobuf"
|
|
20
|
+
require_relative "object_framework/grpc/service"
|
|
21
|
+
require_relative "object_framework/http2/hpack"
|
|
22
|
+
require_relative "object_framework/http2/frame"
|
|
23
|
+
require_relative "object_framework/http2/inbound"
|
|
24
|
+
require_relative "object_framework/grpc/messages"
|
|
25
|
+
require_relative "object_framework/http2/connection"
|
|
26
|
+
require_relative "object_framework/grpc/server"
|
|
27
|
+
|
|
28
|
+
module ObjectFramework
|
|
29
|
+
autoload :SQLite, File.expand_path("object_framework/sqlite", __dir__)
|
|
30
|
+
autoload :Capabilities, File.expand_path("object_framework/capabilities", __dir__)
|
|
31
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: ruby-object-framework
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Gastón Caruso
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies: []
|
|
12
|
+
description: Explicit application composition, scoped execution, Data Mapper persistence,
|
|
13
|
+
HTTP and native gRPC, with an optional SQLite adapter.
|
|
14
|
+
email:
|
|
15
|
+
- gstn.caruso@gmail.com
|
|
16
|
+
executables: []
|
|
17
|
+
extensions: []
|
|
18
|
+
extra_rdoc_files:
|
|
19
|
+
- API.md
|
|
20
|
+
- README.md
|
|
21
|
+
files:
|
|
22
|
+
- API.md
|
|
23
|
+
- README.md
|
|
24
|
+
- THIRD_PARTY_NOTICES.md
|
|
25
|
+
- examples/guides/01_plain_use_case.rb
|
|
26
|
+
- examples/guides/02_composed_application.rb
|
|
27
|
+
- examples/guides/03_order_domain.rb
|
|
28
|
+
- examples/guides/04_scoped_resources.rb
|
|
29
|
+
- examples/guides/05_mapping.rb
|
|
30
|
+
- examples/guides/06_associations.rb
|
|
31
|
+
- examples/guides/07_http.rb
|
|
32
|
+
- examples/guides/08_errors.rb
|
|
33
|
+
- examples/guides/09_sqlite.rb
|
|
34
|
+
- examples/guides/10_grpc.rb
|
|
35
|
+
- examples/guides/11_ractor.rb
|
|
36
|
+
- examples/guides/12_box.rb
|
|
37
|
+
- examples/guides/13_testing.rb
|
|
38
|
+
- examples/guides/manifest.yml
|
|
39
|
+
- examples/orders/application.rb
|
|
40
|
+
- examples/orders/contracts.rb
|
|
41
|
+
- examples/orders/domain.rb
|
|
42
|
+
- examples/orders/export_proto.rb
|
|
43
|
+
- examples/orders/grpc_client.py
|
|
44
|
+
- examples/orders/grpc_server.rb
|
|
45
|
+
- examples/orders/server.rb
|
|
46
|
+
- lib/object_framework.rb
|
|
47
|
+
- lib/object_framework/application.rb
|
|
48
|
+
- lib/object_framework/capabilities.rb
|
|
49
|
+
- lib/object_framework/errors.rb
|
|
50
|
+
- lib/object_framework/execution.rb
|
|
51
|
+
- lib/object_framework/grpc/messages.rb
|
|
52
|
+
- lib/object_framework/grpc/server.rb
|
|
53
|
+
- lib/object_framework/grpc/service.rb
|
|
54
|
+
- lib/object_framework/http/io.rb
|
|
55
|
+
- lib/object_framework/http/presentation.rb
|
|
56
|
+
- lib/object_framework/http/protocol.rb
|
|
57
|
+
- lib/object_framework/http/router.rb
|
|
58
|
+
- lib/object_framework/http/server.rb
|
|
59
|
+
- lib/object_framework/http2/connection.rb
|
|
60
|
+
- lib/object_framework/http2/frame.rb
|
|
61
|
+
- lib/object_framework/http2/hpack.rb
|
|
62
|
+
- lib/object_framework/http2/hpack_tables.rb
|
|
63
|
+
- lib/object_framework/http2/inbound.rb
|
|
64
|
+
- lib/object_framework/memory/storage.rb
|
|
65
|
+
- lib/object_framework/persistence/mapping.rb
|
|
66
|
+
- lib/object_framework/persistence/query.rb
|
|
67
|
+
- lib/object_framework/persistence/session.rb
|
|
68
|
+
- lib/object_framework/persistence/transaction.rb
|
|
69
|
+
- lib/object_framework/protobuf.rb
|
|
70
|
+
- lib/object_framework/sqlite.rb
|
|
71
|
+
- lib/object_framework/sqlite/compiler.rb
|
|
72
|
+
- lib/object_framework/sqlite/schema.rb
|
|
73
|
+
- lib/object_framework/sqlite/storage.rb
|
|
74
|
+
- lib/object_framework/version.rb
|
|
75
|
+
homepage: https://github.com/gstn-caruso/ruby-object-framework
|
|
76
|
+
licenses:
|
|
77
|
+
- Nonstandard
|
|
78
|
+
metadata:
|
|
79
|
+
source_code_uri: https://github.com/gstn-caruso/ruby-object-framework
|
|
80
|
+
documentation_uri: https://gstn-caruso.github.io/ruby-object-framework/
|
|
81
|
+
changelog_uri: https://github.com/gstn-caruso/ruby-object-framework/releases
|
|
82
|
+
allowed_push_host: https://rubygems.org
|
|
83
|
+
rubygems_mfa_required: 'true'
|
|
84
|
+
rdoc_options:
|
|
85
|
+
- "--main"
|
|
86
|
+
- API.md
|
|
87
|
+
- "--visibility"
|
|
88
|
+
- public
|
|
89
|
+
require_paths:
|
|
90
|
+
- lib
|
|
91
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - "~>"
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: 4.0.8
|
|
96
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
97
|
+
requirements:
|
|
98
|
+
- - ">="
|
|
99
|
+
- !ruby/object:Gem::Version
|
|
100
|
+
version: '0'
|
|
101
|
+
requirements: []
|
|
102
|
+
rubygems_version: 4.0.20
|
|
103
|
+
specification_version: 4
|
|
104
|
+
summary: A modular Ruby framework built from collaborating objects
|
|
105
|
+
test_files: []
|