roast-ai 0.4.9 → 0.4.10
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 +4 -4
- data/Gemfile +6 -7
- data/Gemfile.lock +14 -2
- data/dsl/demo/Gemfile +4 -0
- data/dsl/demo/Gemfile.lock +120 -0
- data/dsl/demo/cogs/local.rb +15 -0
- data/dsl/demo/simple_external_cog.rb +17 -0
- data/dsl/plugin-gem-example/.gitignore +8 -0
- data/dsl/plugin-gem-example/Gemfile +13 -0
- data/dsl/plugin-gem-example/Gemfile.lock +178 -0
- data/dsl/plugin-gem-example/lib/other.rb +17 -0
- data/dsl/plugin-gem-example/lib/plugin_gem_example.rb +5 -0
- data/dsl/plugin-gem-example/lib/simple.rb +15 -0
- data/dsl/plugin-gem-example/lib/version.rb +10 -0
- data/dsl/plugin-gem-example/plugin-gem-example.gemspec +28 -0
- data/dsl/prototype.rb +11 -3
- data/dsl/scoped_executors.rb +28 -0
- data/dsl/simple_chat.rb +12 -0
- data/dsl/step_communication.rb +10 -4
- data/lib/roast/dsl/cog/config.rb +6 -1
- data/lib/roast/dsl/cog/input.rb +30 -0
- data/lib/roast/dsl/cog/output.rb +24 -0
- data/lib/roast/dsl/cog/registry.rb +39 -0
- data/lib/roast/dsl/cog/stack.rb +2 -1
- data/lib/roast/dsl/cog/store.rb +8 -5
- data/lib/roast/dsl/cog.rb +49 -28
- data/lib/roast/dsl/cog_input_context.rb +9 -0
- data/lib/roast/dsl/cog_input_manager.rb +47 -0
- data/lib/roast/dsl/cogs/chat.rb +78 -0
- data/lib/roast/dsl/cogs/cmd.rb +97 -20
- data/lib/roast/dsl/cogs/execute.rb +46 -0
- data/lib/roast/dsl/cogs/graph.rb +3 -3
- data/lib/roast/dsl/config_context.rb +2 -47
- data/lib/roast/dsl/config_manager.rb +96 -0
- data/lib/roast/dsl/execution_context.rb +9 -0
- data/lib/roast/dsl/execution_manager.rb +137 -0
- data/lib/roast/dsl/workflow.rb +113 -0
- data/lib/roast/version.rb +1 -1
- data/lib/roast.rb +3 -2
- data/roast.gemspec +1 -0
- data/sorbet/config +1 -0
- data/sorbet/rbi/gems/marcel@1.1.0.rbi +239 -0
- data/sorbet/rbi/gems/{rack@2.2.18.rbi → rack@2.2.19.rbi} +55 -38
- data/sorbet/rbi/gems/ruby_llm@1.8.2.rbi +5703 -0
- data/sorbet/rbi/shims/lib/roast/dsl/cog_input_context.rbi +17 -0
- data/sorbet/rbi/shims/lib/roast/dsl/config_context.rbi +6 -0
- data/sorbet/rbi/shims/lib/roast/dsl/execution_context.rbi +17 -0
- metadata +45 -8
- data/lib/roast/dsl/cog_execution_context.rb +0 -29
- data/lib/roast/dsl/cogs.rb +0 -65
- data/lib/roast/dsl/executor.rb +0 -82
- data/lib/roast/dsl/workflow_execution_context.rb +0 -47
- data/sorbet/rbi/gems/rbs-inline@0.12.0.rbi +0 -2170
- data/sorbet/rbi/shims/lib/roast/dsl/workflow_execution_context.rbi +0 -11
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Roast
|
|
5
|
+
module DSL
|
|
6
|
+
class ConfigManager
|
|
7
|
+
class ConfigManagerError < Roast::Error; end
|
|
8
|
+
class ConfigManagerNotPreparedError < ConfigManagerError; end
|
|
9
|
+
class ConfigManagerAlreadyPreparedError < ConfigManagerError; end
|
|
10
|
+
|
|
11
|
+
#: (Cog::Registry, Array[^() -> void]) -> void
|
|
12
|
+
def initialize(cog_registry, config_procs)
|
|
13
|
+
@cog_registry = cog_registry
|
|
14
|
+
@config_procs = config_procs
|
|
15
|
+
@config_context = ConfigContext.new #: ConfigContext
|
|
16
|
+
@general_configs = {} #: Hash[singleton(Cog), Cog::Config]
|
|
17
|
+
@name_scoped_configs = {} #: Hash[singleton(Cog), Hash[Symbol, Cog::Config]]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
#: () -> void
|
|
21
|
+
def prepare!
|
|
22
|
+
raise ConfigManagerAlreadyPreparedError if preparing? || prepared?
|
|
23
|
+
|
|
24
|
+
@preparing = true
|
|
25
|
+
bind_registered_cogs
|
|
26
|
+
@config_procs.each { |cp| @config_context.instance_eval(&cp) }
|
|
27
|
+
@prepared = true
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
#: () -> bool
|
|
31
|
+
def preparing?
|
|
32
|
+
@preparing ||= false
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
#: () -> bool
|
|
36
|
+
def prepared?
|
|
37
|
+
@prepared ||= false
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
#: (singleton(Cog), ?Symbol?) -> Cog::Config
|
|
41
|
+
def config_for(cog_class, name = nil)
|
|
42
|
+
raise ConfigManagerNotPreparedError unless prepared?
|
|
43
|
+
|
|
44
|
+
# All cogs will always have a config; empty by default if the cog was never explicitly configured
|
|
45
|
+
config = fetch_general_config(cog_class)
|
|
46
|
+
name_scoped_config = fetch_name_scoped_config(cog_class, name) unless name.nil?
|
|
47
|
+
config = config.merge(name_scoped_config) if name_scoped_config
|
|
48
|
+
config
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
#: (singleton(Cog)) -> Cog::Config
|
|
54
|
+
def fetch_general_config(cog_class)
|
|
55
|
+
@general_configs[cog_class] ||= cog_class.config_class.new
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
#: (singleton(Cog), Symbol) -> Cog::Config
|
|
59
|
+
def fetch_name_scoped_config(cog_class, name)
|
|
60
|
+
name_scoped_configs_for_cog = @name_scoped_configs[cog_class] ||= {}
|
|
61
|
+
name_scoped_configs_for_cog[name] ||= cog_class.config_class.new
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
#: () -> void
|
|
65
|
+
def bind_registered_cogs
|
|
66
|
+
@cog_registry.cogs.each { |cog_method_name, cog_class| bind_cog(cog_method_name, cog_class) }
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
#: (Symbol, singleton(Cog)) -> void
|
|
70
|
+
def bind_cog(cog_method_name, cog_class)
|
|
71
|
+
on_config_method = method(:on_config)
|
|
72
|
+
cog_method = proc do |cog_name = nil, &cog_config_proc|
|
|
73
|
+
on_config_method.call(cog_class, cog_name, &cog_config_proc)
|
|
74
|
+
end
|
|
75
|
+
@config_context.instance_eval do
|
|
76
|
+
define_singleton_method(cog_method_name, cog_method)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
#: (singleton(Cog), Symbol) { () -> void } -> void
|
|
81
|
+
def on_config(cog_class, cog_name, &cog_config_proc)
|
|
82
|
+
# Called when the cog method is invoked in the workflow's 'config' block.
|
|
83
|
+
# This allows configuration parameters to be set for the cog generally or for a specific named instance
|
|
84
|
+
config_object = if cog_name.nil?
|
|
85
|
+
fetch_general_config(cog_class)
|
|
86
|
+
else
|
|
87
|
+
fetch_name_scoped_config(cog_class, cog_name)
|
|
88
|
+
end
|
|
89
|
+
# NOTE: Sorbet expects the proc passed to instance_exec to be declared as taking an argument
|
|
90
|
+
# but our cog_config_proc does not get an argument
|
|
91
|
+
config_object.instance_exec(&T.unsafe(cog_config_proc)) if cog_config_proc
|
|
92
|
+
config_object
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Roast
|
|
5
|
+
module DSL
|
|
6
|
+
# Context in which the `execute` block of a workflow is evaluated
|
|
7
|
+
class ExecutionManager
|
|
8
|
+
class ExecutionManagerError < Roast::Error; end
|
|
9
|
+
class ExecutionManagerNotPreparedError < ExecutionManagerError; end
|
|
10
|
+
class ExecutionManagerAlreadyPreparedError < ExecutionManagerError; end
|
|
11
|
+
class ExecutionManagerCurrentlyRunningError < ExecutionManagerError; end
|
|
12
|
+
class ExecutionScopeDoesNotExistError < ExecutionManagerError; end
|
|
13
|
+
class ExecutionScopeNotSpecifiedError < ExecutionManagerError; end
|
|
14
|
+
|
|
15
|
+
#: (Cog::Registry, ConfigManager, Hash[Symbol?, Array[^() -> void]], ?Symbol?) -> void
|
|
16
|
+
def initialize(cog_registry, config_manager, all_execution_procs, scope = nil)
|
|
17
|
+
@cog_registry = cog_registry
|
|
18
|
+
@config_manager = config_manager
|
|
19
|
+
@all_execution_procs = all_execution_procs
|
|
20
|
+
@scope = scope
|
|
21
|
+
@cogs = Cog::Store.new #: Cog::Store
|
|
22
|
+
@cog_stack = Cog::Stack.new #: Cog::Stack
|
|
23
|
+
@execution_context = ExecutionContext.new #: ExecutionContext
|
|
24
|
+
@cog_input_manager = CogInputManager.new(@cog_registry, @cogs) #: CogInputManager
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
#: () -> void
|
|
28
|
+
def prepare!
|
|
29
|
+
raise ExecutionManagerAlreadyPreparedError if preparing? || prepared?
|
|
30
|
+
|
|
31
|
+
@preparing = true
|
|
32
|
+
bind_registered_cogs
|
|
33
|
+
my_execution_procs.each { |ep| @execution_context.instance_eval(&ep) }
|
|
34
|
+
@prepared = true
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def run!
|
|
38
|
+
raise ExecutionManagerNotPreparedError unless prepared?
|
|
39
|
+
raise ExecutionManagerCurrentlyRunningError if running?
|
|
40
|
+
|
|
41
|
+
@running = true
|
|
42
|
+
@cog_stack.map do |name, cog|
|
|
43
|
+
cog.run!(
|
|
44
|
+
@config_manager.config_for(cog.class, name.to_sym),
|
|
45
|
+
cog_input_manager,
|
|
46
|
+
)
|
|
47
|
+
end
|
|
48
|
+
@running = false
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
#: () -> bool
|
|
52
|
+
def preparing?
|
|
53
|
+
@preparing ||= false
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
#: () -> bool
|
|
57
|
+
def prepared?
|
|
58
|
+
@prepared ||= false
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
#: () -> bool
|
|
62
|
+
def running?
|
|
63
|
+
@running ||= false
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
#: () -> CogInputContext
|
|
67
|
+
def cog_input_manager
|
|
68
|
+
raise ExecutionManagerNotPreparedError unless prepared?
|
|
69
|
+
|
|
70
|
+
@cog_input_manager.context
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
#: () -> Array[^() -> void]
|
|
76
|
+
def my_execution_procs
|
|
77
|
+
raise ExecutionScopeDoesNotExistError unless @all_execution_procs.key?(@scope)
|
|
78
|
+
|
|
79
|
+
@all_execution_procs[@scope] || []
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
#: (Symbol, Cog) -> void
|
|
83
|
+
def add_cog_instance(name, cog)
|
|
84
|
+
@cogs.insert(name, cog)
|
|
85
|
+
@cog_stack.push([name, cog])
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# TODO: add typing for output
|
|
89
|
+
#: (Symbol) -> untyped
|
|
90
|
+
def output(name)
|
|
91
|
+
@cogs[name].output
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
#: () -> void
|
|
95
|
+
def bind_registered_cogs
|
|
96
|
+
@cog_registry.cogs.each { |cog_method_name, cog_class| bind_cog(cog_method_name, cog_class) }
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
#: (Symbol, singleton(Cog)) -> void
|
|
100
|
+
def bind_cog(cog_method_name, cog_class)
|
|
101
|
+
on_execute_method = method(:on_execute)
|
|
102
|
+
cog_method = proc do |cog_name = Random.uuid, &cog_input_proc|
|
|
103
|
+
on_execute_method.call(cog_class, cog_name, &cog_input_proc)
|
|
104
|
+
end
|
|
105
|
+
@execution_context.instance_eval do
|
|
106
|
+
define_singleton_method(cog_method_name, cog_method)
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
#: (singleton(Cog), Symbol) { (Cog::Input) -> untyped } -> void
|
|
111
|
+
def on_execute(cog_class, cog_name, &cog_input_proc)
|
|
112
|
+
# Called when the cog method is invoked in the workflow's 'execute' block.
|
|
113
|
+
# This creates the cog instance and prepares it for execution.
|
|
114
|
+
cog_instance = if cog_class == Cogs::Execute
|
|
115
|
+
create_special_execute_cog(cog_name, cog_input_proc)
|
|
116
|
+
else
|
|
117
|
+
cog_class.new(cog_name, cog_input_proc)
|
|
118
|
+
end
|
|
119
|
+
add_cog_instance(cog_name, cog_instance)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
#: (Symbol, ^(Cogs::Execute::Input) -> untyped) -> Cogs::Execute
|
|
123
|
+
def create_special_execute_cog(cog_name, cog_input_proc)
|
|
124
|
+
trigger = proc do |input|
|
|
125
|
+
raise ExecutionScopeNotSpecifiedError unless input.scope.present?
|
|
126
|
+
|
|
127
|
+
em = ExecutionManager.new(@cog_registry, @config_manager, @all_execution_procs, input.scope)
|
|
128
|
+
em.prepare!
|
|
129
|
+
em.run!
|
|
130
|
+
|
|
131
|
+
# TODO: collect the outputs of the cogs in the execution manager that just ran and do something with them
|
|
132
|
+
end
|
|
133
|
+
Cogs::Execute.new(cog_name, cog_input_proc, trigger)
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Roast
|
|
5
|
+
module DSL
|
|
6
|
+
class Workflow
|
|
7
|
+
class WorkflowError < Roast::Error; end
|
|
8
|
+
class WorkflowNotPreparedError < WorkflowError; end
|
|
9
|
+
class WorkflowAlreadyPreparedError < WorkflowError; end
|
|
10
|
+
class WorkflowAlreadyStartedError < WorkflowError; end
|
|
11
|
+
class InvalidCogReference < WorkflowError; end
|
|
12
|
+
|
|
13
|
+
class << self
|
|
14
|
+
#: (String) -> void
|
|
15
|
+
def from_file(workflow_path)
|
|
16
|
+
workflow = new(workflow_path)
|
|
17
|
+
workflow.prepare!
|
|
18
|
+
workflow.start!
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
#: (String) -> void
|
|
23
|
+
def initialize(workflow_path)
|
|
24
|
+
@workflow_path = Pathname.new(workflow_path)
|
|
25
|
+
@workflow_definition = File.read(workflow_path)
|
|
26
|
+
@cog_registry = Cog::Registry.new #: Cog::Registry
|
|
27
|
+
@config_procs = [] #: Array[^() -> void]
|
|
28
|
+
@execution_procs = { nil: [] } #: Hash[Symbol?, Array[^() -> void]]
|
|
29
|
+
@config_manager = nil #: ConfigManager?
|
|
30
|
+
@execution_manager = nil #: ExecutionManager?
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
#: () -> void
|
|
34
|
+
def prepare!
|
|
35
|
+
raise WorkflowAlreadyPreparedError if preparing? || prepared?
|
|
36
|
+
|
|
37
|
+
@preparing = true
|
|
38
|
+
extract_dsl_procs!
|
|
39
|
+
@config_manager = ConfigManager.new(@cog_registry, @config_procs)
|
|
40
|
+
@config_manager.prepare!
|
|
41
|
+
@execution_manager = ExecutionManager.new(@cog_registry, @config_manager, @execution_procs)
|
|
42
|
+
@execution_manager.prepare!
|
|
43
|
+
|
|
44
|
+
@prepared = true
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
#: () -> void
|
|
48
|
+
def start!
|
|
49
|
+
raise WorkflowNotPreparedError unless @config_manager.present? && @execution_manager.present?
|
|
50
|
+
raise WorkflowAlreadyStartedError if started? || completed?
|
|
51
|
+
|
|
52
|
+
@started = true
|
|
53
|
+
@execution_manager.run!
|
|
54
|
+
@completed = true
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
#: () -> bool
|
|
58
|
+
def preparing?
|
|
59
|
+
@preparing ||= false
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
#: () -> bool
|
|
63
|
+
def prepared?
|
|
64
|
+
@prepared ||= false
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
#: () -> bool
|
|
68
|
+
def started?
|
|
69
|
+
@started ||= false
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
#: () -> bool
|
|
73
|
+
def completed?
|
|
74
|
+
@completed ||= false
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
#: { () [self: ConfigContext] -> void } -> void
|
|
78
|
+
def config(&block)
|
|
79
|
+
@config_procs << block
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
#: (?Symbol?) { () [self: ExecutionContext] -> void } -> void
|
|
83
|
+
def execute(scope = nil, &block)
|
|
84
|
+
(@execution_procs[scope] ||= []) << block
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def use(cogs = [], from: nil)
|
|
88
|
+
require from if from
|
|
89
|
+
|
|
90
|
+
Array.wrap(cogs).each do |cog_name|
|
|
91
|
+
path = @workflow_path.realdirpath.dirname.join("cogs/#{cog_name}")
|
|
92
|
+
require path.to_s if from.nil?
|
|
93
|
+
|
|
94
|
+
cog_class_name = cog_name.camelize
|
|
95
|
+
raise InvalidCogReference, "Expected #{cog_class_name} class, not found in #{path}" unless Object.const_defined?(cog_class_name)
|
|
96
|
+
|
|
97
|
+
cog_class = cog_class_name.constantize # rubocop:disable Sorbet/ConstantsFromStrings
|
|
98
|
+
@cog_registry.use(cog_class)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
private
|
|
103
|
+
|
|
104
|
+
# Evaluate the top-level workflow definition
|
|
105
|
+
# This collects the procs passed to `config` and `execute` calls in the workflow definition,
|
|
106
|
+
# but does not evaluate any of them individually yet.
|
|
107
|
+
#: () -> void
|
|
108
|
+
def extract_dsl_procs!
|
|
109
|
+
instance_eval(@workflow_definition)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
data/lib/roast/version.rb
CHANGED
data/lib/roast.rb
CHANGED
|
@@ -28,14 +28,15 @@ require "active_support/core_ext/string"
|
|
|
28
28
|
require "active_support/core_ext/string/inflections"
|
|
29
29
|
require "active_support/isolated_execution_state"
|
|
30
30
|
require "active_support/notifications"
|
|
31
|
-
require "cli/ui"
|
|
32
31
|
require "cli/kit"
|
|
32
|
+
require "cli/ui"
|
|
33
33
|
require "diff/lcs"
|
|
34
34
|
require "json-schema"
|
|
35
35
|
require "raix"
|
|
36
36
|
require "raix/chat_completion"
|
|
37
37
|
require "raix/function_dispatch"
|
|
38
38
|
require "ruby-graphviz"
|
|
39
|
+
require "ruby_llm"
|
|
39
40
|
require "thor"
|
|
40
41
|
require "timeout"
|
|
41
42
|
|
|
@@ -68,7 +69,7 @@ module Roast
|
|
|
68
69
|
|
|
69
70
|
if options[:executor] == "dsl"
|
|
70
71
|
puts "⚠️ WARNING: This is an experimental syntax and may break at any time. Don't depend on it."
|
|
71
|
-
Roast::DSL::
|
|
72
|
+
Roast::DSL::Workflow.from_file(workflow_path)
|
|
72
73
|
else
|
|
73
74
|
expanded_workflow_path = if workflow_path.include?("workflow.yml")
|
|
74
75
|
File.expand_path(workflow_path)
|
data/roast.gemspec
CHANGED
|
@@ -44,6 +44,7 @@ Gem::Specification.new do |spec|
|
|
|
44
44
|
spec.add_dependency("open_router", "~> 0.3")
|
|
45
45
|
spec.add_dependency("raix", "~> 1.0.2")
|
|
46
46
|
spec.add_dependency("ruby-graphviz", "~> 1.2")
|
|
47
|
+
spec.add_dependency("ruby_llm")
|
|
47
48
|
spec.add_dependency("sqlite3", "~> 2.6")
|
|
48
49
|
spec.add_dependency("thor", "~> 1.3")
|
|
49
50
|
spec.add_dependency("zeitwerk", "~> 2.6")
|
data/sorbet/config
CHANGED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
|
|
3
|
+
# DO NOT EDIT MANUALLY
|
|
4
|
+
# This is an autogenerated file for types exported from the `marcel` gem.
|
|
5
|
+
# Please instead update this file by running `bin/tapioca gem marcel`.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# This file is auto-generated. Instead of editing this file, please
|
|
9
|
+
# add MIMEs to data/custom.xml or lib/marcel/mime_type/definitions.rb.
|
|
10
|
+
#
|
|
11
|
+
# source://marcel//lib/marcel.rb#3
|
|
12
|
+
module Marcel; end
|
|
13
|
+
|
|
14
|
+
# @private
|
|
15
|
+
#
|
|
16
|
+
# source://marcel//lib/marcel/tables.rb#9
|
|
17
|
+
Marcel::EXTENSIONS = T.let(T.unsafe(nil), Hash)
|
|
18
|
+
|
|
19
|
+
# @private
|
|
20
|
+
#
|
|
21
|
+
# source://marcel//lib/marcel/tables.rb#2513
|
|
22
|
+
Marcel::MAGIC = T.let(T.unsafe(nil), Array)
|
|
23
|
+
|
|
24
|
+
# Mime type detection
|
|
25
|
+
#
|
|
26
|
+
# source://marcel//lib/marcel/magic.rb#12
|
|
27
|
+
class Marcel::Magic
|
|
28
|
+
# Mime type by type string
|
|
29
|
+
#
|
|
30
|
+
# @return [Magic] a new instance of Magic
|
|
31
|
+
#
|
|
32
|
+
# source://marcel//lib/marcel/magic.rb#16
|
|
33
|
+
def initialize(type); end
|
|
34
|
+
|
|
35
|
+
# Allow comparison with string
|
|
36
|
+
#
|
|
37
|
+
# @return [Boolean]
|
|
38
|
+
#
|
|
39
|
+
# source://marcel//lib/marcel/magic.rb#103
|
|
40
|
+
def ==(other); end
|
|
41
|
+
|
|
42
|
+
# @return [Boolean]
|
|
43
|
+
#
|
|
44
|
+
# source://marcel//lib/marcel/magic.rb#54
|
|
45
|
+
def audio?; end
|
|
46
|
+
|
|
47
|
+
# Returns true if type is child of parent type
|
|
48
|
+
#
|
|
49
|
+
# @return [Boolean]
|
|
50
|
+
#
|
|
51
|
+
# source://marcel//lib/marcel/magic.rb#58
|
|
52
|
+
def child_of?(parent); end
|
|
53
|
+
|
|
54
|
+
# Get mime comment
|
|
55
|
+
#
|
|
56
|
+
# source://marcel//lib/marcel/magic.rb#68
|
|
57
|
+
def comment; end
|
|
58
|
+
|
|
59
|
+
# Allow comparison with string
|
|
60
|
+
#
|
|
61
|
+
# @return [Boolean]
|
|
62
|
+
#
|
|
63
|
+
# source://marcel//lib/marcel/magic.rb#103
|
|
64
|
+
def eql?(other); end
|
|
65
|
+
|
|
66
|
+
# Get string list of file extensions
|
|
67
|
+
#
|
|
68
|
+
# source://marcel//lib/marcel/magic.rb#63
|
|
69
|
+
def extensions; end
|
|
70
|
+
|
|
71
|
+
# source://marcel//lib/marcel/magic.rb#107
|
|
72
|
+
def hash; end
|
|
73
|
+
|
|
74
|
+
# Mediatype shortcuts
|
|
75
|
+
#
|
|
76
|
+
# @return [Boolean]
|
|
77
|
+
#
|
|
78
|
+
# source://marcel//lib/marcel/magic.rb#53
|
|
79
|
+
def image?; end
|
|
80
|
+
|
|
81
|
+
# Returns the value of attribute mediatype.
|
|
82
|
+
#
|
|
83
|
+
# source://marcel//lib/marcel/magic.rb#13
|
|
84
|
+
def mediatype; end
|
|
85
|
+
|
|
86
|
+
# Returns the value of attribute subtype.
|
|
87
|
+
#
|
|
88
|
+
# source://marcel//lib/marcel/magic.rb#13
|
|
89
|
+
def subtype; end
|
|
90
|
+
|
|
91
|
+
# Returns true if type is a text format
|
|
92
|
+
#
|
|
93
|
+
# @return [Boolean]
|
|
94
|
+
#
|
|
95
|
+
# source://marcel//lib/marcel/magic.rb#50
|
|
96
|
+
def text?; end
|
|
97
|
+
|
|
98
|
+
# Return type as string
|
|
99
|
+
#
|
|
100
|
+
# source://marcel//lib/marcel/magic.rb#98
|
|
101
|
+
def to_s; end
|
|
102
|
+
|
|
103
|
+
# Returns the value of attribute type.
|
|
104
|
+
#
|
|
105
|
+
# source://marcel//lib/marcel/magic.rb#13
|
|
106
|
+
def type; end
|
|
107
|
+
|
|
108
|
+
# @return [Boolean]
|
|
109
|
+
#
|
|
110
|
+
# source://marcel//lib/marcel/magic.rb#55
|
|
111
|
+
def video?; end
|
|
112
|
+
|
|
113
|
+
class << self
|
|
114
|
+
# Add custom mime type. Arguments:
|
|
115
|
+
# * <i>type</i>: Mime type
|
|
116
|
+
# * <i>options</i>: Options hash
|
|
117
|
+
#
|
|
118
|
+
# Option keys:
|
|
119
|
+
# * <i>:extensions</i>: String list or single string of file extensions
|
|
120
|
+
# * <i>:parents</i>: String list or single string of parent mime types
|
|
121
|
+
# * <i>:magic</i>: Mime magic specification
|
|
122
|
+
# * <i>:comment</i>: Comment string
|
|
123
|
+
#
|
|
124
|
+
# source://marcel//lib/marcel/magic.rb#30
|
|
125
|
+
def add(type, options); end
|
|
126
|
+
|
|
127
|
+
# Lookup all mime types by magic content analysis.
|
|
128
|
+
# This is a slower operation.
|
|
129
|
+
#
|
|
130
|
+
# source://marcel//lib/marcel/magic.rb#93
|
|
131
|
+
def all_by_magic(io); end
|
|
132
|
+
|
|
133
|
+
# Lookup mime type by file extension
|
|
134
|
+
#
|
|
135
|
+
# source://marcel//lib/marcel/magic.rb#73
|
|
136
|
+
def by_extension(ext); end
|
|
137
|
+
|
|
138
|
+
# Lookup mime type by magic content analysis.
|
|
139
|
+
# This is a slow operation.
|
|
140
|
+
#
|
|
141
|
+
# source://marcel//lib/marcel/magic.rb#86
|
|
142
|
+
def by_magic(io); end
|
|
143
|
+
|
|
144
|
+
# Lookup mime type by filename
|
|
145
|
+
#
|
|
146
|
+
# source://marcel//lib/marcel/magic.rb#80
|
|
147
|
+
def by_path(path); end
|
|
148
|
+
|
|
149
|
+
# @return [Boolean]
|
|
150
|
+
#
|
|
151
|
+
# source://marcel//lib/marcel/magic.rb#113
|
|
152
|
+
def child?(child, parent); end
|
|
153
|
+
|
|
154
|
+
# Removes a mime type from the dictionary. You might want to do this if
|
|
155
|
+
# you're seeing impossible conflicts (for instance, application/x-gmc-link).
|
|
156
|
+
# * <i>type</i>: The mime type to remove. All associated extensions and magic are removed too.
|
|
157
|
+
#
|
|
158
|
+
# source://marcel//lib/marcel/magic.rb#42
|
|
159
|
+
def remove(type); end
|
|
160
|
+
|
|
161
|
+
private
|
|
162
|
+
|
|
163
|
+
# source://marcel//lib/marcel/magic.rb#117
|
|
164
|
+
def magic_match(io, method); end
|
|
165
|
+
|
|
166
|
+
# source://marcel//lib/marcel/magic.rb#127
|
|
167
|
+
def magic_match_io(io, matches, buffer); end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# source://marcel//lib/marcel/mime_type.rb#4
|
|
172
|
+
class Marcel::MimeType
|
|
173
|
+
class << self
|
|
174
|
+
# source://marcel//lib/marcel/mime_type.rb#8
|
|
175
|
+
def extend(type, extensions: T.unsafe(nil), parents: T.unsafe(nil), magic: T.unsafe(nil)); end
|
|
176
|
+
|
|
177
|
+
# Returns the most appropriate content type for the given file.
|
|
178
|
+
#
|
|
179
|
+
# The first argument should be a +Pathname+ or an +IO+. If it is a +Pathname+, the specified
|
|
180
|
+
# file will be opened first.
|
|
181
|
+
#
|
|
182
|
+
# Optional parameters:
|
|
183
|
+
# * +name+: file name, if known
|
|
184
|
+
# * +extension+: file extension, if known
|
|
185
|
+
# * +declared_type+: MIME type, if known
|
|
186
|
+
#
|
|
187
|
+
# The most appropriate type is determined by the following:
|
|
188
|
+
# * type declared by binary magic number data
|
|
189
|
+
# * type declared by the first of file name, file extension, or declared MIME type
|
|
190
|
+
#
|
|
191
|
+
# If no type can be determined, then +application/octet-stream+ is returned.
|
|
192
|
+
#
|
|
193
|
+
# source://marcel//lib/marcel/mime_type.rb#29
|
|
194
|
+
def for(pathname_or_io = T.unsafe(nil), name: T.unsafe(nil), extension: T.unsafe(nil), declared_type: T.unsafe(nil)); end
|
|
195
|
+
|
|
196
|
+
private
|
|
197
|
+
|
|
198
|
+
# source://marcel//lib/marcel/mime_type.rb#36
|
|
199
|
+
def for_data(pathname_or_io); end
|
|
200
|
+
|
|
201
|
+
# source://marcel//lib/marcel/mime_type.rb#62
|
|
202
|
+
def for_declared_type(declared_type); end
|
|
203
|
+
|
|
204
|
+
# source://marcel//lib/marcel/mime_type.rb#54
|
|
205
|
+
def for_extension(extension); end
|
|
206
|
+
|
|
207
|
+
# source://marcel//lib/marcel/mime_type.rb#46
|
|
208
|
+
def for_name(name); end
|
|
209
|
+
|
|
210
|
+
# For some document types (notably Microsoft Office) we recognise the main content
|
|
211
|
+
# type with magic, but not the specific subclass. In this situation, if we can get a more
|
|
212
|
+
# specific class using either the name or declared_type, we should use that in preference
|
|
213
|
+
#
|
|
214
|
+
# source://marcel//lib/marcel/mime_type.rb#89
|
|
215
|
+
def most_specific_type(*candidates); end
|
|
216
|
+
|
|
217
|
+
# source://marcel//lib/marcel/mime_type.rb#79
|
|
218
|
+
def parse_media_type(content_type); end
|
|
219
|
+
|
|
220
|
+
# source://marcel//lib/marcel/mime_type.rb#71
|
|
221
|
+
def with_io(pathname_or_io, &block); end
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# source://marcel//lib/marcel/mime_type.rb#5
|
|
226
|
+
Marcel::MimeType::BINARY = T.let(T.unsafe(nil), String)
|
|
227
|
+
|
|
228
|
+
# @private
|
|
229
|
+
#
|
|
230
|
+
# source://marcel//lib/marcel/tables.rb#1310
|
|
231
|
+
Marcel::TYPE_EXTS = T.let(T.unsafe(nil), Hash)
|
|
232
|
+
|
|
233
|
+
# Cooltalk Audio
|
|
234
|
+
#
|
|
235
|
+
# source://marcel//lib/marcel/tables.rb#2239
|
|
236
|
+
Marcel::TYPE_PARENTS = T.let(T.unsafe(nil), Hash)
|
|
237
|
+
|
|
238
|
+
# source://marcel//lib/marcel/version.rb#4
|
|
239
|
+
Marcel::VERSION = T.let(T.unsafe(nil), String)
|