ollama_chat 0.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.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/.all_images.yml +17 -0
  3. data/.gitignore +9 -0
  4. data/Gemfile +5 -0
  5. data/README.md +159 -0
  6. data/Rakefile +58 -0
  7. data/VERSION +1 -0
  8. data/bin/ollama_chat +5 -0
  9. data/lib/ollama_chat/chat.rb +398 -0
  10. data/lib/ollama_chat/clipboard.rb +23 -0
  11. data/lib/ollama_chat/dialog.rb +94 -0
  12. data/lib/ollama_chat/document_cache.rb +16 -0
  13. data/lib/ollama_chat/follow_chat.rb +60 -0
  14. data/lib/ollama_chat/information.rb +113 -0
  15. data/lib/ollama_chat/message_list.rb +216 -0
  16. data/lib/ollama_chat/message_type.rb +5 -0
  17. data/lib/ollama_chat/model_handling.rb +29 -0
  18. data/lib/ollama_chat/ollama_chat_config.rb +103 -0
  19. data/lib/ollama_chat/parsing.rb +159 -0
  20. data/lib/ollama_chat/source_fetching.rb +173 -0
  21. data/lib/ollama_chat/switches.rb +119 -0
  22. data/lib/ollama_chat/utils/cache_fetcher.rb +38 -0
  23. data/lib/ollama_chat/utils/chooser.rb +53 -0
  24. data/lib/ollama_chat/utils/fetcher.rb +175 -0
  25. data/lib/ollama_chat/utils/file_argument.rb +34 -0
  26. data/lib/ollama_chat/utils.rb +7 -0
  27. data/lib/ollama_chat/version.rb +8 -0
  28. data/lib/ollama_chat.rb +20 -0
  29. data/ollama_chat.gemspec +50 -0
  30. data/spec/assets/api_show.json +63 -0
  31. data/spec/assets/api_tags.json +21 -0
  32. data/spec/assets/conversation.json +14 -0
  33. data/spec/assets/duckduckgo.html +757 -0
  34. data/spec/assets/example.atom +26 -0
  35. data/spec/assets/example.csv +5 -0
  36. data/spec/assets/example.html +10 -0
  37. data/spec/assets/example.pdf +139 -0
  38. data/spec/assets/example.ps +4 -0
  39. data/spec/assets/example.rb +1 -0
  40. data/spec/assets/example.rss +25 -0
  41. data/spec/assets/example.xml +7 -0
  42. data/spec/assets/kitten.jpg +0 -0
  43. data/spec/assets/prompt.txt +1 -0
  44. data/spec/ollama_chat/chat_spec.rb +105 -0
  45. data/spec/ollama_chat/clipboard_spec.rb +29 -0
  46. data/spec/ollama_chat/follow_chat_spec.rb +46 -0
  47. data/spec/ollama_chat/information_spec.rb +50 -0
  48. data/spec/ollama_chat/message_list_spec.rb +132 -0
  49. data/spec/ollama_chat/model_handling_spec.rb +35 -0
  50. data/spec/ollama_chat/parsing_spec.rb +240 -0
  51. data/spec/ollama_chat/source_fetching_spec.rb +54 -0
  52. data/spec/ollama_chat/switches_spec.rb +167 -0
  53. data/spec/ollama_chat/utils/cache_fetcher_spec.rb +43 -0
  54. data/spec/ollama_chat/utils/fetcher_spec.rb +137 -0
  55. data/spec/ollama_chat/utils/file_argument_spec.rb +17 -0
  56. data/spec/spec_helper.rb +46 -0
  57. data/tmp/.keep +0 -0
  58. metadata +476 -0
@@ -0,0 +1,240 @@
1
+ require 'spec_helper'
2
+ require 'pathname'
3
+
4
+ RSpec.describe OllamaChat::Parsing do
5
+ let :chat do
6
+ OllamaChat::Chat.new
7
+ end
8
+
9
+ before do
10
+ stub_request(:get, %r(/api/tags\z)).
11
+ to_return(status: 200, body: asset_json('api_tags.json'))
12
+ stub_request(:post, %r(/api/show\z)).
13
+ to_return(status: 200, body: asset_json('api_show.json'))
14
+ chat
15
+ end
16
+
17
+ describe '#parse_source' do
18
+ it 'can parse HTML' do
19
+ asset_io('example.html') do |io|
20
+ def io.content_type
21
+ 'text/html'
22
+ end
23
+ expect(chat.parse_source(io)).to eq(
24
+ "# My First Heading\n\nMy first paragraph.\n\n"
25
+ )
26
+ end
27
+ end
28
+
29
+ it 'can parse XML' do
30
+ asset_io('example.xml') do |io|
31
+ def io.content_type
32
+ 'text/xml'
33
+ end
34
+ expect(chat.parse_source(io)).to eq(asset_content('example.xml'))
35
+ end
36
+ end
37
+
38
+ it 'can parse CSV' do
39
+ asset_io('example.csv') do |io|
40
+ def io.content_type
41
+ 'text/csv'
42
+ end
43
+ expect(chat.parse_source(io)).to eq(<<EOT)
44
+ name: John Doe
45
+ age: 32
46
+ occupation: Software Engineer
47
+
48
+ name: Jane Smith
49
+ age: 28
50
+ occupation: Marketing Manager
51
+
52
+ name: Bob Johnson
53
+ age: 45
54
+ occupation: Retired
55
+
56
+ name: Alice Brown
57
+ age: 25
58
+ occupation: Student
59
+
60
+ EOT
61
+ end
62
+ end
63
+
64
+ it 'can parse RSS' do
65
+ asset_io('example.rss') do |io|
66
+ def io.content_type
67
+ 'application/rss+xml'
68
+ end
69
+ expect(chat.parse_source(io)).to start_with(<<~EOT)
70
+ # Example News Feed
71
+
72
+ ## [New Study Shows Benefits of Meditation](https://example.com/article/meditation-benefits)
73
+
74
+ EOT
75
+ end
76
+ end
77
+
78
+ it 'can parse RSS with content type XML' do
79
+ asset_io('example.rss') do |io|
80
+ def io.content_type
81
+ 'text/xml'
82
+ end
83
+ expect(chat.parse_source(io)).to start_with(<<~EOT)
84
+ # Example News Feed
85
+
86
+ ## [New Study Shows Benefits of Meditation](https://example.com/article/meditation-benefits)
87
+
88
+ EOT
89
+ end
90
+ end
91
+
92
+ it 'can parse Atom' do
93
+ asset_io('example.atom') do |io|
94
+ def io.content_type
95
+ 'application/atom+xml'
96
+ end
97
+ expect(chat.parse_source(io)).to start_with(<<~EOT)
98
+ # Example Feed
99
+
100
+ ## [New Study Shows Benefits of Meditation](https://example.com/article/meditation-benefits)
101
+
102
+ updated on 2024-01-01T12:00:00Z
103
+
104
+
105
+
106
+ ## [Local Business Opens New Location](https://example.com/article/local-business-new-location)
107
+
108
+ updated on 2024-01-02T10:00:00Z
109
+ EOT
110
+ end
111
+ end
112
+
113
+ it 'can parse Postscript' do
114
+ asset_io('example.ps') do |io|
115
+ def io.content_type
116
+ 'application/postscript'
117
+ end
118
+ expect(chat.parse_source(io)).to eq("Hello World!")
119
+ end
120
+ end
121
+
122
+ it 'can parse PDF' do
123
+ asset_io('example.pdf') do |io|
124
+ def io.content_type
125
+ 'application/pdf'
126
+ end
127
+ expect(chat.parse_source(io)).to eq("Hello World!")
128
+ end
129
+ end
130
+
131
+ it 'can parse other texts' do
132
+ asset_io('example.rb') do |io|
133
+ def io.content_type
134
+ 'application/x-ruby'
135
+ end
136
+ expect(chat.parse_source(io)).to eq(%{puts "Hello World!"\n})
137
+ end
138
+ end
139
+ end
140
+
141
+ describe '#parse_content' do
142
+ it 'can parse tags' do
143
+ content, tags = chat.parse_content("see #foobar …", [])
144
+ expect(content).to eq 'see #foobar …'
145
+ expect(tags).to include('foobar')
146
+ end
147
+
148
+ it 'can parse https URLs' do
149
+ stub_request(:get, "https://www.example.com/foo.html").
150
+ with(headers: { 'Host' => 'www.example.com' }).
151
+ to_return(
152
+ status: 200,
153
+ body: "",
154
+ headers: { 'Content-Type' => 'text/html' }
155
+ )
156
+ content, = chat.parse_content('https://www.example.com/foo.html', [])
157
+ expect(content).to include 'Imported "https://www.example.com/foo.html"'
158
+ end
159
+
160
+ it 'can parse file URLs' do
161
+ content, = chat.parse_content("see file://#{Dir.pwd}/spec/assets/example.html", [])
162
+ expect(content).to include(<<~EOT)
163
+ Imported "#{Pathname.pwd.join('spec/assets/example.html')}":
164
+
165
+ # My First Heading
166
+
167
+ My first paragraph.
168
+ EOT
169
+ end
170
+
171
+ it 'can parse file paths' do
172
+ content, = chat.parse_content("see #{Dir.pwd}/spec/assets/example.html", [])
173
+ expect(content).to include(<<~EOT)
174
+ Imported "#{Pathname.pwd.join('spec/assets/example.html')}":
175
+
176
+ # My First Heading
177
+
178
+ My first paragraph.
179
+ EOT
180
+ end
181
+
182
+ it 'can add images' do
183
+ images = []
184
+ expect(chat).to receive(:add_image).
185
+ with(images, kind_of(IO), %r(/spec/assets/kitten.jpg\z)).
186
+ and_call_original
187
+ chat.parse_content('./spec/assets/kitten.jpg', images)
188
+ expect(images.size).to eq 1
189
+ expect(images.first).to be_a Ollama::Image
190
+ end
191
+
192
+ context 'document_policy' do
193
+ it 'can be ignoring' do
194
+ chat.document_policy = 'ignoring'
195
+ c = "see #{Dir.pwd}/spec/assets/example.html"
196
+ content, = chat.parse_content(c, [])
197
+ expect(content).to eq(c)
198
+ end
199
+
200
+ it 'can be importing' do
201
+ chat.document_policy = 'importing'
202
+ c = "see #{Dir.pwd}/spec/assets/example.html"
203
+ content, = chat.parse_content(c, [])
204
+ expect(content).to include(<<~EOT)
205
+ Imported "#{Pathname.pwd.join('spec/assets/example.html')}":
206
+
207
+ # My First Heading
208
+
209
+ My first paragraph.
210
+ EOT
211
+ end
212
+
213
+ it 'can be embedding' do
214
+ chat.document_policy = 'embedding'
215
+ c = "see #{Dir.pwd}/spec/assets/example.html"
216
+ expect(chat).to receive(:embed_source).with(
217
+ kind_of(IO),
218
+ Pathname.pwd.join('spec/assets/example.html').to_s
219
+ )
220
+ content, = chat.parse_content(c, [])
221
+ end
222
+
223
+ it 'can be summarizing' do
224
+ chat.document_policy = 'summarizing'
225
+ c = "see #{Dir.pwd}/spec/assets/example.html"
226
+ content, = chat.parse_content(c, [])
227
+ expect(content).to start_with(<<~EOT)
228
+ see #{Pathname.pwd.join('spec/assets/example.html')}
229
+
230
+ Generate an abstract summary of the content in this document using
231
+ 100 words:
232
+
233
+ # My First Heading
234
+
235
+ My first paragraph.
236
+ EOT
237
+ end
238
+ end
239
+ end
240
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe OllamaChat::SourceFetching do
4
+ let :chat do
5
+ OllamaChat::Chat.new
6
+ end
7
+
8
+ before do
9
+ stub_request(:get, %r(/api/tags\z)).
10
+ to_return(status: 200, body: asset_json('api_tags.json'))
11
+ stub_request(:post, %r(/api/show\z)).
12
+ to_return(status: 200, body: asset_json('api_show.json'))
13
+ allow(chat).to receive(:location).and_return(double(on?: false))
14
+ end
15
+
16
+ it 'can import' do
17
+ expect(chat.import('./spec/assets/example.html')).to start_with(<<~EOT)
18
+ Imported "./spec/assets/example.html":
19
+
20
+ # My First Heading
21
+
22
+ My first paragraph.
23
+ EOT
24
+ end
25
+
26
+ it 'can summarize' do
27
+ expect(chat.summarize('./spec/assets/example.html')).to start_with(<<~EOT)
28
+ Generate an abstract summary of the content in this document using
29
+ 100 words:
30
+
31
+ # My First Heading
32
+
33
+ My first paragraph.
34
+ EOT
35
+ end
36
+
37
+ it 'can embed' do
38
+ expect(chat).to receive(:fetch_source).with(
39
+ './spec/assets/example.html'
40
+ )
41
+ expect(chat.embed('./spec/assets/example.html')).to eq(
42
+ 'This source was now embedded: ./spec/assets/example.html'
43
+ )
44
+ end
45
+
46
+ it 'can search web' do
47
+ stub_request(:get, "https://www.duckduckgo.com/html/?q=foo").
48
+ with(headers: { 'Host'=>'www.duckduckgo.com' }).
49
+ to_return(status: 200, body: asset_content('duckduckgo.html'), headers: {})
50
+ expect(chat.search_web('foo').first.to_s).to eq(
51
+ 'https://en.wikipedia.org/wiki/Foo_Fighters'
52
+ )
53
+ end
54
+ end
@@ -0,0 +1,167 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe OllamaChat::Switches do
4
+ describe OllamaChat::Switches::Switch do
5
+ let :switch do
6
+ described_class.new(
7
+ :test,
8
+ config: config,
9
+ msg: {
10
+ true => "Enabled.",
11
+ false => "Disabled.",
12
+ }
13
+ )
14
+ end
15
+
16
+ context 'default to false' do
17
+ let :config do
18
+ double(test?: false)
19
+ end
20
+
21
+
22
+ it 'can be switched on' do
23
+ expect {
24
+ switch.set(true)
25
+ }.to change {
26
+ switch.on? && !switch.off?
27
+ }.from(false).to(true)
28
+ end
29
+
30
+ it 'can be toggled on' do
31
+ expect(STDOUT).to receive(:puts).with('Enabled.')
32
+ expect {
33
+ switch.toggle
34
+ }.to change {
35
+ switch.on? && !switch.off?
36
+ }.from(false).to(true)
37
+ end
38
+ end
39
+
40
+ context 'default to false' do
41
+ let :config do
42
+ double(test?: true)
43
+ end
44
+
45
+ it 'can be switched on' do
46
+ expect {
47
+ switch.set(false)
48
+ }.to change {
49
+ switch.on? && !switch.off?
50
+ }.from(true).to(false)
51
+ end
52
+
53
+ it 'can be toggled off' do
54
+ expect(STDOUT).to receive(:puts).with('Disabled.')
55
+ expect {
56
+ switch.toggle
57
+ }.to change {
58
+ switch.on? && !switch.off?
59
+ }.from(true).to(false)
60
+ end
61
+ end
62
+ end
63
+
64
+ describe OllamaChat::Switches::CombinedSwitch do
65
+ describe 'off' do
66
+ let :config do
67
+ double(test1?: true, test2?: false)
68
+ end
69
+
70
+ let :switch1 do
71
+ OllamaChat::Switches::Switch.new(
72
+ :test1,
73
+ config: config,
74
+ msg: {
75
+ true => "Enabled.",
76
+ false => "Disabled.",
77
+ }
78
+ )
79
+ end
80
+
81
+ let :switch2 do
82
+ OllamaChat::Switches::Switch.new(
83
+ :test2,
84
+ config: config,
85
+ msg: {
86
+ true => "Enabled.",
87
+ false => "Disabled.",
88
+ }
89
+ )
90
+ end
91
+
92
+ let :switch do
93
+ described_class.new(
94
+ value: -> { switch1.on? && switch2.off? },
95
+ msg: {
96
+ true => "Enabled.",
97
+ false => "Disabled.",
98
+ }
99
+ )
100
+ end
101
+
102
+ it 'can be switched off 2' do
103
+ expect {
104
+ switch2.set(true)
105
+ }.to change {
106
+ switch.on? && !switch.off?
107
+ }.from(true).to(false)
108
+ end
109
+
110
+ it 'can be switched off 1' do
111
+ expect {
112
+ switch1.set(false)
113
+ }.to change {
114
+ switch.on? && !switch.off?
115
+ }.from(true).to(false)
116
+ end
117
+ end
118
+
119
+ describe 'on' do
120
+ let :config do
121
+ double(test1?: false, test2?: true)
122
+ end
123
+
124
+ let :switch1 do
125
+ OllamaChat::Switches::Switch.new(
126
+ :test1,
127
+ config: config,
128
+ msg: {
129
+ true => "Enabled.",
130
+ false => "Disabled.",
131
+ }
132
+ )
133
+ end
134
+
135
+ let :switch2 do
136
+ OllamaChat::Switches::Switch.new(
137
+ :test2,
138
+ config: config,
139
+ msg: {
140
+ true => "Enabled.",
141
+ false => "Disabled.",
142
+ }
143
+ )
144
+ end
145
+
146
+ let :switch do
147
+ described_class.new(
148
+ value: -> { switch1.on? && switch2.off? },
149
+ msg: {
150
+ true => "Enabled.",
151
+ false => "Disabled.",
152
+ }
153
+ )
154
+ end
155
+
156
+ it 'can be switched on' do
157
+ switch
158
+ expect {
159
+ switch1.set(true)
160
+ switch2.set(false)
161
+ }.to change {
162
+ switch.on? && !switch.off?
163
+ }.from(false).to(true)
164
+ end
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe OllamaChat::Utils::CacheFetcher do
4
+ let :url do
5
+ 'https://www.example.com/hello'
6
+ end
7
+
8
+ let :cache do
9
+ double('RedisCache')
10
+ end
11
+
12
+ let :fetcher do
13
+ described_class.new(cache).expose
14
+ end
15
+
16
+ it 'can be instantiated' do
17
+ expect(fetcher).to be_a described_class
18
+ end
19
+
20
+ it 'has #get' do
21
+ expect(cache).to receive(:[]).with('body-69ce405ab83f42dffa9fd22bbd47783f').and_return 'world'
22
+ expect(cache).to receive(:[]).with('content_type-69ce405ab83f42dffa9fd22bbd47783f').and_return 'text/plain'
23
+ yielded_io = nil
24
+ block = -> io { yielded_io = io }
25
+ fetcher.get(url, &block)
26
+ expect(yielded_io).to be_a StringIO
27
+ expect(yielded_io.read).to eq 'world'
28
+ end
29
+
30
+ it '#get needs block' do
31
+ expect { fetcher.get(url) }.to raise_error(ArgumentError)
32
+ end
33
+
34
+ it 'has #put' do
35
+ io = StringIO.new('world')
36
+ io.extend(OllamaChat::Utils::Fetcher::HeaderExtension)
37
+ io.content_type = MIME::Types['text/plain'].first
38
+ io.ex = 666
39
+ expect(cache).to receive(:set).with('body-69ce405ab83f42dffa9fd22bbd47783f', 'world', ex: 666)
40
+ expect(cache).to receive(:set).with('content_type-69ce405ab83f42dffa9fd22bbd47783f', 'text/plain', ex: 666)
41
+ fetcher.put(url, io)
42
+ end
43
+ end
@@ -0,0 +1,137 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe OllamaChat::Utils::Fetcher do
4
+ let :url do
5
+ 'https://www.example.com/hello'
6
+ end
7
+
8
+ let :fetcher do
9
+ described_class.new.expose
10
+ end
11
+
12
+ it 'can be instantiated' do
13
+ expect(fetcher).to be_a described_class
14
+ end
15
+
16
+ it 'has .get' do
17
+ expect(described_class).to receive(:new).and_return double(get: true)
18
+ described_class.get(url)
19
+ end
20
+
21
+ it 'can #get with streaming' do
22
+ stub_request(:get, url).
23
+ with(headers: fetcher.headers).
24
+ to_return(
25
+ status: 200,
26
+ body: 'world',
27
+ headers: { 'Content-Type' => 'text/plain' },
28
+ )
29
+ fetcher.get(url) do |tmp|
30
+ expect(tmp).to be_a Tempfile
31
+ expect(tmp.read).to eq 'world'
32
+ expect(tmp.content_type).to eq 'text/plain'
33
+ end
34
+ end
35
+
36
+ it 'can #get without ssl peer verification' do
37
+ fetcher = described_class.new(
38
+ http_options: { ssl_verify_peer: false }
39
+ ).expose
40
+ stub_request(:get, url).
41
+ with(headers: fetcher.headers).
42
+ to_return(
43
+ status: 200,
44
+ body: 'world',
45
+ headers: { 'Content-Type' => 'text/plain' },
46
+ )
47
+ expect(Excon).to receive(:new).with(
48
+ url,
49
+ hash_including(ssl_verify_peer: false)
50
+ ).and_call_original
51
+ fetcher.get(url) do |tmp|
52
+ expect(tmp).to be_a Tempfile
53
+ expect(tmp.read).to eq 'world'
54
+ expect(tmp.content_type).to eq 'text/plain'
55
+ end
56
+ end
57
+
58
+ it 'can #get and fallback from streaming' do
59
+ stub_request(:get, url).
60
+ with(headers: fetcher.headers).
61
+ to_return(
62
+ { status: 501 },
63
+ {
64
+ status: 200,
65
+ body: 'world',
66
+ headers: { 'Content-Type' => 'text/plain' },
67
+ }
68
+ )
69
+ fetcher.get(url) do |tmp|
70
+ expect(tmp).to be_a Tempfile
71
+ expect(tmp.read).to eq 'world'
72
+ expect(tmp.content_type).to eq 'text/plain'
73
+ end
74
+ end
75
+
76
+ it 'can #get and finally fail' do
77
+ stub_request(:get, url).
78
+ with(headers: fetcher.headers).
79
+ to_return(status: 500)
80
+ expect(STDERR).to receive(:puts).with(/cannot.*get.*#{url}/i)
81
+ fetcher.get(url) do |tmp|
82
+ expect(tmp).to be_a StringIO
83
+ expect(tmp.read).to eq ''
84
+ expect(tmp.content_type).to eq 'text/plain'
85
+ end
86
+ end
87
+
88
+ it 'can redirect' do
89
+ expect(fetcher.middlewares).to include Excon::Middleware::RedirectFollower
90
+ end
91
+
92
+ it 'can .read' do
93
+ described_class.read(__FILE__) do |file|
94
+ expect(file).to be_a File
95
+ expect(file.read).to include 'can .read'
96
+ expect(file.content_type).to eq 'application/x-ruby'
97
+ end
98
+ end
99
+
100
+ it 'can .execute' do
101
+ described_class.execute('echo -n hello world') do |file|
102
+ expect(file).to be_a Tempfile
103
+ expect(file.read).to eq 'hello world'
104
+ expect(file.content_type).to eq 'text/plain'
105
+ end
106
+ end
107
+
108
+ it 'can .execute and fail' do
109
+ expect(IO).to receive(:popen).and_raise StandardError
110
+ expect(STDERR).to receive(:puts).with(/cannot.*execute.*foobar/i)
111
+ described_class.execute('foobar') do |file|
112
+ expect(file).to be_a StringIO
113
+ expect(file.read).to be_empty
114
+ expect(file.content_type).to eq 'text/plain'
115
+ end
116
+ end
117
+
118
+ describe '.normalize_url' do
119
+ it 'can handle umlauts' do
120
+ expect(described_class.normalize_url('https://foo.de/bär')).to eq(
121
+ 'https://foo.de/b%C3%A4r'
122
+ )
123
+ end
124
+
125
+ it 'can handle escaped umlauts' do
126
+ expect(described_class.normalize_url('https://foo.de/b%C3%A4r')).to eq(
127
+ 'https://foo.de/b%C3%A4r'
128
+ )
129
+ end
130
+
131
+ it 'can remove #anchors' do
132
+ expect(described_class.normalize_url('https://foo.de#bar')).to eq(
133
+ 'https://foo.de'
134
+ )
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe OllamaChat::Utils::FileArgument do
4
+ it 'it can return content' do
5
+ expect(described_class.get_file_argument('foo')).to eq 'foo'
6
+ end
7
+
8
+ it 'it can return content at path' do
9
+ expect(described_class.get_file_argument(asset('prompt.txt'))).to include\
10
+ 'test prompt'
11
+ end
12
+
13
+ it 'it can return default content' do
14
+ expect(described_class.get_file_argument('', default: 'foo')).to eq 'foo'
15
+ expect(described_class.get_file_argument(nil, default: 'foo')).to eq 'foo'
16
+ end
17
+ end
@@ -0,0 +1,46 @@
1
+ if ENV['START_SIMPLECOV'].to_i == 1
2
+ require 'simplecov'
3
+ SimpleCov.start do
4
+ add_filter "#{File.basename(File.dirname(__FILE__))}/"
5
+ end
6
+ end
7
+ require 'rspec'
8
+ require 'tins/xt/expose'
9
+ begin
10
+ require 'debug'
11
+ rescue LoadError
12
+ end
13
+ require 'webmock/rspec'
14
+ WebMock.disable_net_connect!
15
+ require 'ollama_chat'
16
+
17
+ def asset(name)
18
+ File.join(__dir__, 'assets', name)
19
+ end
20
+
21
+ def asset_content(name)
22
+ File.read(File.join(__dir__, 'assets', name))
23
+ end
24
+
25
+ def asset_io(name, &block)
26
+ io = File.new(File.join(__dir__, 'assets', name))
27
+ if block
28
+ begin
29
+ block.call(io)
30
+ ensure
31
+ io.close
32
+ end
33
+ else
34
+ io
35
+ end
36
+ end
37
+
38
+ def asset_json(name)
39
+ JSON(JSON(File.read(asset(name))))
40
+ end
41
+
42
+ RSpec.configure do |config|
43
+ config.before(:suite) do
44
+ infobar.show = nil
45
+ end
46
+ end
data/tmp/.keep ADDED
File without changes