elephrame 0.4.6 → 0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +2 -0
- data/Gemfile.lock +24 -11
- data/README.md +6 -4
- data/elephrame.gemspec +2 -1
- data/examples/ebooks.rb +24 -0
- data/examples/getting_started.org +484 -0
- data/examples/markov.rb +20 -0
- data/examples/markov_files/manifesto.txt +1886 -0
- data/examples/{combined.rb → periodic_interact.rb} +0 -0
- data/examples/tracery_simple.rb +2 -0
- data/lib/elephrame/mix/bots.rb +317 -7
- data/lib/elephrame/mix/generative.rb +244 -0
- data/lib/elephrame/mix/tracery.rb +15 -12
- data/lib/elephrame/rest/rest.rb +1 -1
- data/lib/elephrame/streaming/command.rb +1 -1
- data/lib/elephrame/streaming/reply.rb +1 -1
- data/lib/elephrame/streaming/streaming.rb +3 -2
- data/lib/elephrame/util/account.rb +16 -0
- data/lib/elephrame/util/status.rb +16 -5
- data/lib/elephrame/version.rb +1 -1
- data/lib/elephrame.rb +1 -1
- metadata +38 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: da4cb8e7330a90534de1df0dfcd992669f3406081d8b84432026961116976184
|
4
|
+
data.tar.gz: '08828035932340977b30d9db147c5df568b08d5b5dfa835967ab6940d808ac1e'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 447b5a423594675b6d949ad2bb29a67d74db3cb278484c133f9213b10a622d3607a0a09ad2e55c363d7c76651fb1690091965f09e17d1534a2f9ed20b2ed017d
|
7
|
+
data.tar.gz: ed0d5bd6ee5869626d235de919b468ca768f14b8bb1b5da5dd6574edd8eccf3f10f6fa7ac6e3badf769ea6879ce5b233cb05436b0eb3fa4ece2e9be5972e7847
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
elephrame (0.
|
4
|
+
elephrame (0.5)
|
5
|
+
htmlentities (~> 4.0)
|
6
|
+
moo_ebooks (~> 1)
|
5
7
|
moostodon (~> 0.4.0)
|
6
8
|
rufus-scheduler
|
7
9
|
tracery (~> 0.7)
|
@@ -13,13 +15,16 @@ GEM
|
|
13
15
|
public_suffix (>= 2.0.2, < 4.0)
|
14
16
|
buftok (0.2.0)
|
15
17
|
concurrent-ruby (1.1.5)
|
16
|
-
domain_name (0.5.
|
18
|
+
domain_name (0.5.20190701)
|
17
19
|
unf (>= 0.0.5, < 1.0.0)
|
18
|
-
et-orbi (1.1
|
20
|
+
et-orbi (1.2.1)
|
19
21
|
tzinfo
|
20
|
-
fugit (1.1
|
21
|
-
et-orbi (~> 1.1, >= 1.1.
|
22
|
+
fugit (1.3.1)
|
23
|
+
et-orbi (~> 1.1, >= 1.1.8)
|
22
24
|
raabro (~> 1.1)
|
25
|
+
highscore (1.2.1)
|
26
|
+
whatlanguage (>= 1.0.0)
|
27
|
+
htmlentities (4.3.4)
|
23
28
|
http (3.3.0)
|
24
29
|
addressable (~> 2.3)
|
25
30
|
http-cookie (~> 1.0)
|
@@ -30,32 +35,40 @@ GEM
|
|
30
35
|
http-form_data (2.1.1)
|
31
36
|
http_parser.rb (0.6.0)
|
32
37
|
minitest (5.11.3)
|
38
|
+
moo_ebooks (1.1.0)
|
39
|
+
highscore (~> 1.2)
|
40
|
+
htmlentities (~> 4.3)
|
33
41
|
moostodon (0.4.0)
|
34
42
|
addressable (~> 2.5)
|
35
43
|
buftok (~> 0)
|
36
44
|
http (~> 3.0)
|
37
45
|
oj (~> 3.3)
|
38
|
-
oj (3.
|
39
|
-
public_suffix (3.
|
46
|
+
oj (3.8.1)
|
47
|
+
public_suffix (3.1.1)
|
40
48
|
raabro (1.1.6)
|
41
49
|
rake (10.5.0)
|
42
|
-
rufus-scheduler (3.
|
43
|
-
fugit (~> 1.1, >= 1.1.
|
50
|
+
rufus-scheduler (3.6.0)
|
51
|
+
fugit (~> 1.1, >= 1.1.6)
|
44
52
|
tracery (0.7.7)
|
45
53
|
tzinfo (2.0.0)
|
46
54
|
concurrent-ruby (~> 1.0)
|
55
|
+
tzinfo-data (1.2019.2)
|
56
|
+
tzinfo (>= 1.0.0)
|
47
57
|
unf (0.1.4)
|
48
58
|
unf_ext
|
49
|
-
unf_ext (0.0.7.
|
59
|
+
unf_ext (0.0.7.6)
|
60
|
+
whatlanguage (1.0.6)
|
50
61
|
|
51
62
|
PLATFORMS
|
52
63
|
ruby
|
64
|
+
x64-mingw32
|
53
65
|
|
54
66
|
DEPENDENCIES
|
55
67
|
bundler (~> 1.17)
|
56
68
|
elephrame!
|
57
69
|
minitest (~> 5.0)
|
58
70
|
rake (~> 10.0)
|
71
|
+
tzinfo-data
|
59
72
|
|
60
73
|
BUNDLED WITH
|
61
|
-
1.17.
|
74
|
+
1.17.3
|
data/README.md
CHANGED
@@ -19,11 +19,11 @@ gem 'elephrame'
|
|
19
19
|
|
20
20
|
And then execute:
|
21
21
|
|
22
|
-
|
22
|
+
bundle
|
23
23
|
|
24
24
|
Or install it yourself as:
|
25
25
|
|
26
|
-
|
26
|
+
gem install elephrame
|
27
27
|
|
28
28
|
## Quickstart
|
29
29
|
|
@@ -34,15 +34,17 @@ require 'elephrame'
|
|
34
34
|
|
35
35
|
my_bot = Elephrame::Bots::Periodic.new '3h'
|
36
36
|
|
37
|
-
my_bot.run
|
37
|
+
my_bot.run do |bot|
|
38
38
|
bot.post("i'm gay")
|
39
|
-
|
39
|
+
end
|
40
40
|
```
|
41
41
|
|
42
42
|
$ INSTANCE="https://mastodon.social" TOKEN="your_access_token" ruby bot.rb
|
43
43
|
|
44
44
|
Check the [examples](https://github.com/theZacAttacks/elephrame/tree/master/examples) directory for more example bots
|
45
45
|
|
46
|
+
If you're new to ruby development in general there is also a [getting started](https://github.com/theZacAttacks/elephrame/tree/master/examples/getting_started.org) document in the examples folder that I would recommend you to read. It takes a high level approach to getting started with ruby, some basic syntax, working with gems, basic project structure, and more!
|
47
|
+
|
46
48
|
### Bot Types
|
47
49
|
|
48
50
|
So far the framework support 6 bot types: Periodic, Interact, PeroidInteract, Reply, Command, Watcher
|
data/elephrame.gemspec
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
lib = File.expand_path("../lib", __FILE__)
|
3
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
3
|
require "elephrame/version"
|
@@ -42,5 +41,7 @@ Gem::Specification.new do |spec|
|
|
42
41
|
|
43
42
|
spec.add_dependency 'rufus-scheduler'
|
44
43
|
spec.add_dependency 'moostodon', '~> 0.4.0'
|
44
|
+
spec.add_dependency 'moo_ebooks', '~> 1'
|
45
45
|
spec.add_dependency 'tracery', '~> 0.7'
|
46
|
+
spec.add_dependency 'htmlentities', '~>4.0'
|
46
47
|
end
|
data/examples/ebooks.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'elephrame'
|
2
|
+
|
3
|
+
# So, we want to create an ebook bot
|
4
|
+
# all of the hardwork is done in the backend by the framework!
|
5
|
+
#
|
6
|
+
# we just need to make sure the account we're posting from is set up right
|
7
|
+
# make sure that the ebooks account is following all of the accounts you
|
8
|
+
# want to generate posts from (e.g., if you just want it to be a personal
|
9
|
+
# ebooks bot then just have it follow you,
|
10
|
+
# if you want it to generate posts from everyone
|
11
|
+
# in a group then make sure it follows them all)
|
12
|
+
#
|
13
|
+
# once that's taken care of we need to tell the framework some options for our bot
|
14
|
+
# how often to post, how often to get new statuses from the accounts it's following
|
15
|
+
# what the CW should be for all of its posts (this is polite ;3 )
|
16
|
+
# what the lowest level visiblility setting we should grab to generate from
|
17
|
+
#
|
18
|
+
# thats just what ive supplied in this example, but there are more options!
|
19
|
+
# to see them all please check the documentation (see main README for link)
|
20
|
+
bot = Elephrame::Bots::EbooksBot.new '1m', update_interval: '2d',
|
21
|
+
cw: 'ebooks post', scrape_privacy: 'unlisted'
|
22
|
+
|
23
|
+
# run the bot!
|
24
|
+
bot.run
|
@@ -0,0 +1,484 @@
|
|
1
|
+
* Getting Started
|
2
|
+
|
3
|
+
** Table of Contents
|
4
|
+
|
5
|
+
- [[#ruby][Ruby]]
|
6
|
+
+ [[#installing][Installing]]
|
7
|
+
+ [[#playing-around][Playing around]]
|
8
|
+
+ [[#basic-syntax][Basic Syntax]]
|
9
|
+
+ [[#variables][Variables]]
|
10
|
+
+ [[#constants][Constants]]
|
11
|
+
+ [[#methods][Methods]]
|
12
|
+
+ [[#string-interpolation][String Interpolation]]
|
13
|
+
+ [[#blocks][Blocks]]
|
14
|
+
+ [[#more-info][More Info]]
|
15
|
+
- [[#gems][Gems]]
|
16
|
+
+ [[#what-are-gems][What are Gems?]]
|
17
|
+
+ [[#install-gems][Install Gems]]
|
18
|
+
+ [[#bundler][Bundler]]
|
19
|
+
- [[#running-a-script][Running a Script]]
|
20
|
+
+ [[#without-bundler][Without Bundler]]
|
21
|
+
+ [[#with-bundler][With Bundler]]
|
22
|
+
- [[#elephrame][Elephrame]]
|
23
|
+
+ [[#bot-types][Bot Types]]
|
24
|
+
+ [[#putting-it-all-together][Putting It All Together]]
|
25
|
+
+ [[#getting-more-advanced][Getting More Advanced]]
|
26
|
+
|
27
|
+
** Ruby
|
28
|
+
:PROPERTIES:
|
29
|
+
:CUSTOM_ID: ruby
|
30
|
+
:END:
|
31
|
+
|
32
|
+
*** Installing
|
33
|
+
:PROPERTIES:
|
34
|
+
:CUSTOM_ID: installing
|
35
|
+
:END:
|
36
|
+
If you use Linux/BSD then use your package manager to install ruby.
|
37
|
+
|
38
|
+
If you're on Mac you should have an older version of ruby installed. If you want to install a newer version I would recommend looking into [[https://brew.sh][homebrew]] and using it to install an updated ruby version.
|
39
|
+
|
40
|
+
If you're on Windows there is [[https://rubyinstaller.org/downloads/][RubyInstaller]]. Make sure you choose the one that has the devkit! It's important uwu
|
41
|
+
|
42
|
+
Once you have ruby installed we can check and make sure!
|
43
|
+
|
44
|
+
Open up your command line (cmd on Windows, Terminal on Linux/BSD/Mac) and type in =ruby --version=
|
45
|
+
|
46
|
+
If everything has been set up properly it'll print out the version of ruby you're using!
|
47
|
+
|
48
|
+
*** Playing around
|
49
|
+
:PROPERTIES:
|
50
|
+
:CUSTOM_ID: playing-around
|
51
|
+
:END:
|
52
|
+
To play around in an interactive environment open up your command line and type in =irb= (Interactive RuBy)
|
53
|
+
|
54
|
+
This drops you into an interactive ruby shell where you are free to experiment and play around with new ideas without having to write an entirely new file.
|
55
|
+
|
56
|
+
Feel free to play around in this! Any code I have written in here can be executed in this environment.
|
57
|
+
|
58
|
+
*** Basic Syntax
|
59
|
+
:PROPERTIES:
|
60
|
+
:CUSTOM_ID: basic-syntax
|
61
|
+
:END:
|
62
|
+
There are a lot of data types in ruby:
|
63
|
+
|
64
|
+
- strings
|
65
|
+
- hash tables
|
66
|
+
- arrays
|
67
|
+
- integers
|
68
|
+
- floating point numbers
|
69
|
+
- files
|
70
|
+
- symbols
|
71
|
+
- ... and a lot more!
|
72
|
+
|
73
|
+
I'm going to go over how a few of these different data types are represented in ruby.
|
74
|
+
|
75
|
+
Strings in ruby can be written in a few different ways: 'this is a string', "So is this" (this difference will be covered later!)
|
76
|
+
|
77
|
+
Numbers (floating point or integers) are the easiest to write because it's just a number! E.g., 4, 7.5, 220, -10
|
78
|
+
|
79
|
+
Arrays are just a list of other objects and are represented like this: [1, 2, 3], ["First", "Second", "Third"]
|
80
|
+
|
81
|
+
Hash tables are basically arrays that allow you to reference bits of data out of them using words. They look very similar to arrays, so don't get confused! E.g., { first: 1, second: 2 }
|
82
|
+
|
83
|
+
*** Variables
|
84
|
+
:PROPERTIES:
|
85
|
+
:CUSTOM_ID: variables
|
86
|
+
:END:
|
87
|
+
In ruby you can store data in 'holders' called variables. Imagine it's like putting water into a jug, you're just storing it in a place you know for later!
|
88
|
+
|
89
|
+
It's as easy as this:
|
90
|
+
|
91
|
+
#+BEGIN_SRC ruby
|
92
|
+
variable = "Testing"
|
93
|
+
#+END_SRC
|
94
|
+
|
95
|
+
Variables can be named anything, so long as they don't contain certain special characters or start with a number or a capital letter.
|
96
|
+
|
97
|
+
Invalid variable names:
|
98
|
+
|
99
|
+
#+BEGIN_SRC ruby
|
100
|
+
1variable
|
101
|
+
#+END_SRC
|
102
|
+
|
103
|
+
Valid variable names:
|
104
|
+
|
105
|
+
#+BEGIN_SRC ruby
|
106
|
+
variable1
|
107
|
+
test_variable
|
108
|
+
really_long_variable_name
|
109
|
+
#+END_SRC
|
110
|
+
|
111
|
+
Variablese can be reused as many times as you want. So if you have some code like this:
|
112
|
+
|
113
|
+
#+BEGIN_SRC ruby
|
114
|
+
my_variable = 15
|
115
|
+
my_variable = my_variable + 3
|
116
|
+
#+END_SRC
|
117
|
+
|
118
|
+
Then it would store the result of 18 back into =my_variable=!
|
119
|
+
|
120
|
+
*** Constants
|
121
|
+
:PROPERTIES:
|
122
|
+
:CUSTOM_ID: constants
|
123
|
+
:END:
|
124
|
+
Constants are like variables, but instead of being able to change them on the fly they remain the same (constant!).
|
125
|
+
|
126
|
+
How do we tell variables apart from constants? It's easy! All constants are capitalized.
|
127
|
+
|
128
|
+
This is a constant: =ImportantConstant= and this is a variable: =important_variable=
|
129
|
+
|
130
|
+
Constants can only be defined once and whatever data you put into one stays there. So be careful that you won't need to modify anything after you put it into a constant.
|
131
|
+
|
132
|
+
*** Methods
|
133
|
+
:PROPERTIES:
|
134
|
+
:CUSTOM_ID: methods
|
135
|
+
:END:
|
136
|
+
|
137
|
+
Methods are chunks of code that are grouped underneath a single name.
|
138
|
+
They allow a developer to easily reuse code across a project.
|
139
|
+
|
140
|
+
To define a method you need to do the following:
|
141
|
+
|
142
|
+
#+BEGIN_SRC ruby
|
143
|
+
def example
|
144
|
+
end
|
145
|
+
#+END_SRC
|
146
|
+
|
147
|
+
Any code that you put between the line starting with =def= and the line starting with =end= will be able to run by just writing =example=!
|
148
|
+
|
149
|
+
if you wanted to be able to pass data into methods we can do that, too!
|
150
|
+
|
151
|
+
#+BEGIN_SRC ruby
|
152
|
+
def example(param1, param2)
|
153
|
+
end
|
154
|
+
#+END_SRC
|
155
|
+
|
156
|
+
you now would call example this: =example(1,2)= and any code inside of the method would have access to =1,2= through the variables =param1, param2=!
|
157
|
+
|
158
|
+
*** String Interpolation
|
159
|
+
:PROPERTIES:
|
160
|
+
:CUSTOM_ID: string-interpolation
|
161
|
+
:END:
|
162
|
+
Okay so let's go back to strings and the differences between strings 'like this' and strings "like this".
|
163
|
+
|
164
|
+
Let's say you've got a variable named =output_data= and you wanted to print it out with some text around it.
|
165
|
+
In other programming language you'd have to do something like this:
|
166
|
+
|
167
|
+
#+BEGIN_SRC python
|
168
|
+
"Here's the data " + output_data + " that I found!"
|
169
|
+
#+END_SRC
|
170
|
+
|
171
|
+
but ruby allows for a really nifty thing called String Interpolation.
|
172
|
+
Here's how it looks:
|
173
|
+
|
174
|
+
#+BEGIN_SRC ruby
|
175
|
+
"Here's the data #{output_data} that I found!"
|
176
|
+
#+END_SRC
|
177
|
+
|
178
|
+
As you can tell, it makes it look a lot nicer and a lot easier to add variables into strings!
|
179
|
+
|
180
|
+
Not only can you put variables into strings like this, you can also put method calls! Any kind of code can go in there!
|
181
|
+
|
182
|
+
#+BEGIN_SRC ruby
|
183
|
+
"Some really cool data: #{my_cool_method()}"
|
184
|
+
#+END_SRC
|
185
|
+
|
186
|
+
*** Blocks
|
187
|
+
:PROPERTIES:
|
188
|
+
:CUSTOM_ID: blocks
|
189
|
+
:END:
|
190
|
+
|
191
|
+
Blocks are a fairly unique thing to ruby. They allow you do define code and pass them as parameters to methods. Here's an example:
|
192
|
+
|
193
|
+
#+BEGIN_SRC ruby
|
194
|
+
example_method do
|
195
|
+
puts "Hello from a block!"
|
196
|
+
end
|
197
|
+
#+END_SRC
|
198
|
+
|
199
|
+
Everything between (and including) =do= and =end= is a block! You can pass it to functions, and if they support accepting blocks they'll be able to run whatever code you include! This is useful, but it's made even more useful because data can be passed *in* to a block as well. Here's an example of how that looks:
|
200
|
+
|
201
|
+
#+BEGIN_SRC ruby
|
202
|
+
example_method2 do |data, data2|
|
203
|
+
puts "Hello from a block!"
|
204
|
+
puts "I recieved this data: #{data}"
|
205
|
+
puts "I recieved this data as well: #{data2}"
|
206
|
+
end
|
207
|
+
#+END_SRC
|
208
|
+
|
209
|
+
Think about the syntax like this: =data= and =data2= are *sliding* into the block. That's why they need the =|= s on either side of them! Otherwise how will they safely get in there? :P
|
210
|
+
|
211
|
+
*** More info
|
212
|
+
:PROPERTIES:
|
213
|
+
:CUSTOM_ID: more-info
|
214
|
+
:END:
|
215
|
+
|
216
|
+
If this quick intro to ruby has sparked your interest and you want to know more about it, i recommend this [[https://poignant.guide/book/chapter-3.html][guide]]. it can be a bit much at some points, but i found it a great introduction to ruby!
|
217
|
+
|
218
|
+
** Gems
|
219
|
+
:PROPERTIES:
|
220
|
+
:CUSTOM_ID: gems
|
221
|
+
:END:
|
222
|
+
|
223
|
+
*** What are Gems?
|
224
|
+
:PROPERTIES:
|
225
|
+
:CUSTOM_ID: what-are-gems
|
226
|
+
:END:
|
227
|
+
In the world of ruby third-party libraries are referred to as gems. They are offered by many places, but the primary source of gems is [[https://rubygems.org][RubyGems]]. There are a *lot* of gems there. Go and check some of them out!
|
228
|
+
|
229
|
+
*** Install Gems
|
230
|
+
:PROPERTIES:
|
231
|
+
:CUSTOM_ID: install-gems
|
232
|
+
:END:
|
233
|
+
Knowing about gems is nice and all but how do you get them onto your system? Well, when you installed ruby you got a nice little utility installed, called =gem=.
|
234
|
+
|
235
|
+
So let's go back to your command line, if you're still in =irb= you can either open a new window or type =quit= to exit it. Once you're back at the main command line interface run =gem -h= to have the gem utility print out a little help text.
|
236
|
+
|
237
|
+
Let's go ahead and install a gem that we'll be using for the next section: bundler.
|
238
|
+
|
239
|
+
=gem install bundler=
|
240
|
+
|
241
|
+
*** Bundler
|
242
|
+
:PROPERTIES:
|
243
|
+
:CUSTOM_ID: bundler
|
244
|
+
:END:
|
245
|
+
Bundler is a cool utility that allows you to install gems on a per-project level, keeping the system gem cache clean! If you're following along then you should have it installed now, so lets see some of what it can do: =bundle -h=
|
246
|
+
|
247
|
+
As you can see there are a lot of subcommands! The ones that you'll primarily be using are 'install' and 'exec'. The install command, appropriately installs a gem onto your system. The exec command is a little more abstract. It takes whatever other commands after 'exec' and runs them in the context of that project.
|
248
|
+
|
249
|
+
So if you have a certain gem installed in a project and you want to play around with using it with =irb= then you would run =bundle exec irb= and then you'd be able to have an interactive playground with all the gems from that project!
|
250
|
+
|
251
|
+
**** Gemfile
|
252
|
+
:PROPERTIES:
|
253
|
+
:CUSTOM_ID: gemfile
|
254
|
+
:END:
|
255
|
+
This is neat and all, but how does bundler know what gems a specific project needs? Well, thats where the Gemfile comes into play. The Gemfile contains the source, specifications, and versions of any gems you want to use in your project. Here is an example Gemfile that tells bundler to use the elephrame gem!
|
256
|
+
|
257
|
+
#+BEGIN_SRC ruby
|
258
|
+
source 'https://rubygems.org'
|
259
|
+
|
260
|
+
gem 'elephrame'
|
261
|
+
#+END_SRC
|
262
|
+
|
263
|
+
There are a lot of extra options that you can use in a Gemfile, but at its basest this is how to use one!
|
264
|
+
|
265
|
+
**** Project Structure
|
266
|
+
:PROPERTIES:
|
267
|
+
:CUSTOM_ID: project-structure
|
268
|
+
:END:
|
269
|
+
So now that we've got a basic Gemfile, where do we put it? It belongs at the top level of your project! So, assuming we have our project in its own folder and our project's main ruby file is called =main.rb=, our file structure would look something like this:
|
270
|
+
|
271
|
+
#+BEGIN_SRC
|
272
|
+
project_folder/
|
273
|
+
project_folder/Gemfile
|
274
|
+
project_folder/main.rb
|
275
|
+
#+END_SRC
|
276
|
+
|
277
|
+
And that's it!
|
278
|
+
|
279
|
+
After you have your project setup like this, you need to tell bundler to install your gems. To do that all you have to do is have your project opened in your command line and run =bundle install= and it'll get the rest set up properly!
|
280
|
+
|
281
|
+
** Running a script
|
282
|
+
:PROPERTIES:
|
283
|
+
:CUSTOM_ID: running-a-script
|
284
|
+
:END:
|
285
|
+
After you've put all the work into a cool app or project you'd want to be able to run it right? Since ruby is an interpreted language it doesn't need to be compiled before we execute it. However, this also means that we can't just execute our new program, we have to tell the ruby interpretor to read the file and start executing it.
|
286
|
+
|
287
|
+
Both of the following examples assume a project strutcure like the above.
|
288
|
+
|
289
|
+
*** Without Bundler
|
290
|
+
:PROPERTIES:
|
291
|
+
:CUSTOM_ID: without-bundler
|
292
|
+
:END:
|
293
|
+
If your project does not use bundler then there are a few steps you don't have to take, so we can just jump right to executing the script.
|
294
|
+
|
295
|
+
Open your command line interface, go to your project's folder and execute: =ruby main.rb=
|
296
|
+
|
297
|
+
|
298
|
+
*** With Bundler
|
299
|
+
:PROPERTIES:
|
300
|
+
:CUSTOM_ID: with-bundler
|
301
|
+
:END:
|
302
|
+
If your project does use bundler then we have to first make sure that all of your gem dependecies are up to date: =bundle install=
|
303
|
+
|
304
|
+
Once that finishes, open your command line interface, go to your project's folder and execute: =bundle exec ruby main.rb=
|
305
|
+
|
306
|
+
We use =bundle exec= because we need ruby to run in the context of the project and use the gems that the project needs.
|
307
|
+
|
308
|
+
|
309
|
+
** Elephrame
|
310
|
+
:PROPERTIES:
|
311
|
+
:CUSTOM_ID: elephrame
|
312
|
+
:END:
|
313
|
+
|
314
|
+
elephrame is a high level framework for creating bots for mastodon/pleroma. It abstracts away a lot of the routines that a bot developer would have to write in order to get started, providing 'templates' that you can overwrite with your own custom functionality.
|
315
|
+
|
316
|
+
|
317
|
+
*** Bot Types
|
318
|
+
:PROPERTIES:
|
319
|
+
:CUSTOM_ID: bot-types
|
320
|
+
:END:
|
321
|
+
|
322
|
+
elephrame has many different types of bots, here's a list of the different types and their intended purposes:
|
323
|
+
|
324
|
+
- Periodic: posts statuses on a specific schedule or interval
|
325
|
+
- Interact: provides ways to call code when an account gets an interaction (boost, favorite, reply, follow)
|
326
|
+
- PeriodInteract: combines the above two functionalities
|
327
|
+
- Command: provides an easy way to create bots that wait for specific commands before doing anything ('!help', '!update', etc.)
|
328
|
+
- Watcher: watches a specific timeline (global, local, hashtag, home) for updates and runs code when it sees posts
|
329
|
+
- TraceryBot: very similar to PeriodInteract, except it provides shortcuts for using tracery style grammar files
|
330
|
+
- EbooksBot: scans all posts from an account or accounts and generates new posts/replies based off of that input
|
331
|
+
- Markov-bot: scans a text file and generates posts/replies based off of that input
|
332
|
+
|
333
|
+
*** Putting It All Together
|
334
|
+
:PROPERTIES:
|
335
|
+
:CUSTOM_ID: putting-it-all-together
|
336
|
+
:END:
|
337
|
+
|
338
|
+
Okay! Enough explanation, lets create a bot!
|
339
|
+
|
340
|
+
Assuming you have ruby installed and set up properly, create a folder to hold your files. I'll name mine =getting-started-example=
|
341
|
+
|
342
|
+
Once the folder is created, lets go and create our Gemfile. Open your text editor and create a new file in your folder named =Gemfile= and inside of it put the following:
|
343
|
+
|
344
|
+
#+BEGIN_SRC ruby
|
345
|
+
source 'https://rubygems.org'
|
346
|
+
|
347
|
+
gem 'elephrame'
|
348
|
+
#+END_SRC
|
349
|
+
|
350
|
+
Once you have done that, make sure you save it and open up your command line. You'll want to go to your project folder, and once there do a quick =bundle install=
|
351
|
+
|
352
|
+
That will install your gems that you've specified in your Gemfile. Your project folder should look something like this (I'm going to use my folder name, just pretend it's yours!):
|
353
|
+
|
354
|
+
#+BEGIN_SRC
|
355
|
+
getting-started-example/
|
356
|
+
getting-started-example/Gemfile
|
357
|
+
getting-started-example/Gemfile.lock
|
358
|
+
#+END_SRC
|
359
|
+
|
360
|
+
Now, back in your text editor, create a new file in your folder called =main.rb= and enter this into it (don't worry, we'll go over it line by line in a second):
|
361
|
+
|
362
|
+
#+BEGIN_SRC ruby
|
363
|
+
require 'elephrame'
|
364
|
+
|
365
|
+
ExampleBot = Elephrame::Bots::Periodic.new '10s'
|
366
|
+
|
367
|
+
ExampleBot.run do |bot|
|
368
|
+
bot.post("Hello, world!")
|
369
|
+
end
|
370
|
+
#+END_SRC
|
371
|
+
|
372
|
+
Let's break that down!
|
373
|
+
|
374
|
+
#+BEGIN_SRC ruby
|
375
|
+
require 'elephrame'
|
376
|
+
#+END_SRC
|
377
|
+
|
378
|
+
This first line loads the elephrame library. We call the process whereby ruby loads an external library =requiring= that library. When you =require= a library it gets loaded into the current ruby process and allows us to use code that is a part of it. Usually you'll want to keep any =require= statements at the top of your ruby programs, so that anyone who reads through your code knows what all is bring loaded!
|
379
|
+
|
380
|
+
#+BEGIN_SRC ruby
|
381
|
+
ExampleBot = Elephrame::Bots::Periodic.new '10s'
|
382
|
+
#+END_SRC
|
383
|
+
|
384
|
+
This second line shows us creating a new Periodic bot (=Elephrame::Bots::Periodic.new=), passing it ='10s'= and assigning it to the constant =ExampleBot=. In ruby objects can 'live' in a 'package'. 'Packages' are like folders in your filesystem, however instead of being separated with an '/' or '\' they're separated with '::'. So one way to look at this is 'use the Periodic object in the Bots folder of Elephrame'. The =.new= at the end is saying 'create a new instance of this object'. We're passing in ='10s'= because a Periodic bot needs to know how often it needs to post, this is saying 'post every 10 seconds'.
|
385
|
+
|
386
|
+
Putting all of that together: "create a new instance of the Periodic object from the Bots folder of Elephrame, tell it to post every 10 seconds, and put that bot inside of ExampleBot"
|
387
|
+
|
388
|
+
#+BEGIN_SRC ruby
|
389
|
+
ExampleBot.run do |bot|
|
390
|
+
bot.post("Hello, world!")
|
391
|
+
end
|
392
|
+
#+END_SRC
|
393
|
+
|
394
|
+
Now we're getting to the tricky parts! =ExampleBot.run= is a method that takes a block which is what elephrame does when it runs the bot. So, like explained above, we do a block (the =do ... end= parts). This block passes out a parameter which gives us access to the bot letting us post, among other things! The next line, =bot.post("Hello, world!")= is the logic that runs every time the bot is supposed to run. It tells the framework to simply post the status "Hello, world!". There are many options that the =post= method supports, but for this simple case just providing the status to post will do.
|
395
|
+
|
396
|
+
Now that we've gone over it, make sure you save it! Your project folder should now look something like this:
|
397
|
+
|
398
|
+
#+BEGIN_SRC
|
399
|
+
getting-started-example/
|
400
|
+
getting-started-example/Gemfile
|
401
|
+
getting-started-example/Gemfile.lock
|
402
|
+
getting-started-example/main.rb
|
403
|
+
#+END_SRC
|
404
|
+
|
405
|
+
Now that we've got all of the files set up, we need to get our bot's token! Without a token our bot can't make or read posts. Open Mastodon (it can be your account for now, but I would encourage you to make a separate account for your bot once it's finished), and open the settings. There will be an option on the side for 'Development' settings. Open that, and then generate a new application token. Set the name to "My Elephrame Example", leaving the homepage blank and the redirect URI set to the default. You can give the bot any permissions you want, but this example bot needs (at least) the write:status permission. Once you've filled out the necessary fields go and click 'save' at the bottom. It will take you back to the main development menu, except your newly created application will be an option to click. Go ahead and click on it and copy the access token it shows. This token is very special and is what allows your bot to connect to Mastodon!
|
406
|
+
|
407
|
+
Open up your command line, and run the following in your project folder:
|
408
|
+
|
409
|
+
Linux/MacOS: ~INSTANCE="https://your.instance" TOKEN="yourToken" bundle exec ruby main.rb~
|
410
|
+
|
411
|
+
Windows:
|
412
|
+
|
413
|
+
#+BEGIN_SRC bat
|
414
|
+
set INSTANCE=https://your.instance
|
415
|
+
set TOKEN=yourToken
|
416
|
+
bundle exec ruby main.rb
|
417
|
+
#+END_SRC
|
418
|
+
|
419
|
+
|
420
|
+
If everything worked properly then running these commands will cause your command line to appear to hang up, as though it's waiting for input. That means your bot is working!
|
421
|
+
|
422
|
+
If you have your Mastodon account open (the account you got the token from) then after 10 seconds you should see a post from your account saying "Hello, World!". Since this is the only code our bot has it will continue posting this every 10 seconds forever.
|
423
|
+
|
424
|
+
Congratulations! You've made your first Mastodon bot! :3
|
425
|
+
|
426
|
+
*** Getting More Advanced
|
427
|
+
:PROPERTIES:
|
428
|
+
:CUSTOM_ID: getting-more-advanced
|
429
|
+
:END:
|
430
|
+
|
431
|
+
Now that you've gotten your first bot under your belt, let's expand on it! Let's add in the ability for the bot to respond to replies!
|
432
|
+
|
433
|
+
To do this, we're going to change the base type of the bot to =PeriodInteract= and add in some code to handle what happens when we get a reply.
|
434
|
+
|
435
|
+
Reopen =main.rb= in your text editor if you don't still have it open and edit it until it resembles the following:
|
436
|
+
|
437
|
+
#+BEGIN_SRC ruby
|
438
|
+
require 'elephrame'
|
439
|
+
|
440
|
+
ExampleBot = Elephrame::Bots::PeriodInteract.new '10s'
|
441
|
+
|
442
|
+
ExampleBot.on_reply do |bot, post|
|
443
|
+
bot.reply("Hello, user!")
|
444
|
+
end
|
445
|
+
|
446
|
+
ExampleBot.run do |bot|
|
447
|
+
bot.post("Hello, world!")
|
448
|
+
end
|
449
|
+
#+END_SRC
|
450
|
+
|
451
|
+
Let's break those changes down a bit!
|
452
|
+
|
453
|
+
First things first: we changed what kind of bot we're using from =Periodic= to =PeriodicInteract=.
|
454
|
+
|
455
|
+
#+BEGIN_SRC ruby
|
456
|
+
ExampleBot.on_reply do |bot, post|
|
457
|
+
bot.reply("Hello, user!")
|
458
|
+
end
|
459
|
+
#+END_SRC
|
460
|
+
|
461
|
+
We also added in a new method, =on_reply=. It looks very similar to how we use =run= doesn't it? That's because we do use it the exact same way! PeriodInteract allows us to react whenever the bot's account receives any kind of interaction through =on_fave=, =on_boost=, =on_follow=, and =on_reply= methods. Each of these methods accept a block just like the =run= method does, however, these methods pass in another object besides just the main bot one like =run= does. They pass in =bot= (a reference to the main bot object) and =post= (a reference to the post that received the interaction [except in the case of =on_reply=, which receives the reply itself]). The code inside the block is also slightly different than that of the =run= method in that instead of using the =bot.post= method we use the =bot.reply= method. That method, as you may have guessed, this makes the bot reply to the new mention with ="Hello, user!"=.
|
462
|
+
|
463
|
+
Saving and running it from your command line will have your bot posting every 10 seconds and also replying to any user who replies to one of their posts!
|
464
|
+
|
465
|
+
|
466
|
+
This is good and all, but it feels so impersonal, but we can fix that!
|
467
|
+
|
468
|
+
Change the =on_reply= code to this:
|
469
|
+
|
470
|
+
#+BEGIN_SRC ruby
|
471
|
+
ExampleBot.on_reply do |bot, post|
|
472
|
+
user_name = post.account.display_name
|
473
|
+
bot.reply("Hello, #{user_name}!")
|
474
|
+
end
|
475
|
+
#+END_SRC
|
476
|
+
|
477
|
+
What we have now will respond back to a reply with their display name! To accomplish this we've combined a lot of the basics that we've covered above!
|
478
|
+
|
479
|
+
To start with, we save the display name for the account that the reply came from (=post.account.display_name=), and put it into the reply string using string interpolation (="Hello, #{user_name}!"=).
|
480
|
+
|
481
|
+
Let me explain how we got the account's display name. Each post object contains a lot of data about itself including the =account= it came from, the =content= of the post, it's =id=, it's =spoiler_text= (Content Warning), and much more! The account object is very similar, containing it's =id=, =username=, =acct= (full account handle e.g., example@test.lol), and =display_name=.
|
482
|
+
|
483
|
+
*Note: most data exposed through Mastodon objects can be found [[https://docs.joinmastodon.org/api/entities/][here]].*
|
484
|
+
|
data/examples/markov.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'elephrame'
|
2
|
+
|
3
|
+
# tell the bot how often to post, and where to find it's source material,
|
4
|
+
# then we go and set options for it
|
5
|
+
marxkov = Elephrame::Bots::MarkovBot.new '3h', 'markov_files',
|
6
|
+
visibility: 'unlisted', cw: 'markov post'
|
7
|
+
|
8
|
+
# then we tell the bot to post
|
9
|
+
marxkov.run
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
|