# 将简单的 Ruby 文件转换为 Ruby gem

**URL:** https://meta.discourse.org/t/transforming-simple-ruby-files-into-a-ruby-gem/103399
**Category:** Development
**Created:** [2018年十二月3日 21:56 UTC](https://meta.discourse.org/t/transforming-simple-ruby-files-into-a-ruby-gem/103399 "2018-12-03T21:56:30Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![SebastianADW](https://avatars.discourse-cdn.com/v4/letter/s/7bcc69/32.png) [@SebastianADW](https://meta.discourse.org/u/SebastianADW)
#### Post date: [2018年十二月3日 21:56 UTC](https://meta.discourse.org/t/transforming-simple-ruby-files-into-a-ruby-gem/103399/1 "2018-12-03T21:56:30Z")

</div>

Hey,

i am trying to create my first plugin for discourse. I already have the ruby code working fine. I have 4 different ruby files with different kind of methods in it, i like to have them splitted. And a Gemfile and a Gemfile.lock  
How can i transform them now into a Discourse Plugin?  
I already read the Plugin Beginner Tutorial, but it focused on JavaScript Code and not so much on pure ruby code i guess? I am just not sure where to put my files. Is it possible to let them split up and copy the code of the “main” file into the plugin.rb ?  
I didnt use any kind of class definitions or something like that just tried to split different functionality in different files and methods.  
Where do i have to put the Gemfile and the Gemfile.lock

Tried it local but it didnt find the twitter gem which is necessary for it to work, i dont know where the issue came from.

---

<div class="post-metadata">

### Author: ![blake](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/blake/32/157322_2.png) [@blake](https://meta.discourse.org/u/blake)
#### Post date: [2018年十二月4日 03:09 UTC](https://meta.discourse.org/t/transforming-simple-ruby-files-into-a-ruby-gem/103399/2 "2018-12-04T03:09:00Z")

</div>

Glad to here you are working on your first plugin 🙂. I would look at the [examples of other plugins](https://github.com/search?p=4&q=topic%3Adiscourse-plugin+org%3Adiscourse&type=Repositories) and see how they do the ruby side of things.

I don’t think your plugin actually needs to have a Gemfile, but you need to specify all of your [dependencies and sub-dependencies](https://meta.discourse.org/t/specify-external-gem-dependencies-for-plugins/16430/4) inside of your `plugin.rb` file. Discourse will then install all of the gems when it loads the plugin. See this example:

> <https://github.com/xfalcox/discourse-backups-to-dropbox/blob/master/plugin.rb>

> [@SebastianADW](#):
>
> I have 4 different ruby files with different kind of methods in it, i like to have them splitted.

Any files your plugin uses you can put inside of the “lib” folder and then require them inside of `plugin.rb`.

> <https://github.com/discourse/discourse-data-explorer/blob/main/plugin.rb#L579>

---

<div class="post-metadata">

### Author: ![SebastianADW](https://avatars.discourse-cdn.com/v4/letter/s/7bcc69/32.png) [@SebastianADW](https://meta.discourse.org/u/SebastianADW)
#### Post date: [2018年十二月5日 20:33 UTC](https://meta.discourse.org/t/transforming-simple-ruby-files-into-a-ruby-gem/103399/3 "2018-12-05T20:33:02Z")

</div>

Yeah thanks for your response!  
I tried to follow all the advices and format the dependencies like the other plugins.

But i always get that kind of error when i try to start the rails server:

`/.rvm/gems/ruby-2.5.1/gems/bootsnap-1.3.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require’: cannot load such file – twitter (LoadError)`

i required twitter in the files where i need it put this in the normal plugin.rb

```
gem "bundler"
gem "net"
gem "twitter"

```

(obviously there are more gems i put in like this, thats just for an example)  
Do you have any idea why its not working?  
I also tried to specify the version of the gem like that `gem "twitter", "6.2"` and add the required false statement, but still the same error.  
Maybe good to know, its a local discourse server

I think i just dont get how the gems are working in the plugin environment, cause i always get errors regarding them, for example i also get: you are specifying gem i18n in … however it does not exist …

---

<div class="post-metadata">

### Author: ![blake](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/blake/32/157322_2.png) [@blake](https://meta.discourse.org/u/blake)
#### Post date: [2018年十二月7日 20:15 UTC](https://meta.discourse.org/t/transforming-simple-ruby-files-into-a-ruby-gem/103399/4 "2018-12-07T20:15:30Z")

</div>

> [@SebastianADW](#):
>
> Do you have any idea why its not working?

Not exactly, but I still think it is dependency issues and not specifying the gems correctly.

> [@SebastianADW](#):
>
> I also tried to specify the version of the gem like that `gem "twitter", "6.2"`

I think it has to be the full version number like `6.2.0`. I also don’t think you need to specify “bundler” or “net”.

Apparently when writing a plugin you have to go through dependency hell 🔥 to get it all working and happy. Basically the workflow I go though is start with the main gem that I want. In this case it is the twitter gem. Make sure this one is always listed as the last gem in your plugin.rb file.

```
gem 'twitter', '6.2.0', { require: false }

```

Then I look at all the [runtime dependencies for this gem](https://rubygems.org/gems/twitter) and ONE AT A TIME list each dependency with each subdependency above the twitter gem. Run `bundle exec rails s` between each dependency and check for `(Gem::MissingSpecError)` to know which dependency to add next.

Apparently the addressable gem (2.5.2, instead of 2.3.8) is already required by a discourse gem, so it should be safe to ignore. (You can run `gem dependency addressable --reverse-dependencies` to see which gems require it).

Your plugin.rb should look something like:

```plaintext
gem 'buftok', '0.2.0', { require: false }
gem 'equalizer', '0.0.11', { require: false }
gem 'domain_name', '0.5.20180417', { require: false }
gem 'http-cookie', '1.0.3', { require: false }
gem 'http-form_data', '2.0.0', { require: false }
gem 'http_parser.rb', '0.6.0', { require: false }
gem 'http', '3.3.0', { require: false }
gem 'memoizable', '0.4.2', { require: false }
gem 'naught', '1.1.0', { require: false }
gem 'simple_oauth', '0.3.1', { require: false }
gem 'twitter', '6.2.0', { require: false }

#gem 'addressable', '2.3.8', { require: false } # Already required in Discourse
#gem 'multipart-post', '2.0.0', { require: false } # Already required in Discourse

require 'twitter'

client = Twitter::REST::Client.new do |config|
  config.consumer_key = "YOUR_CONSUMER_KEY"
  config.consumer_secret = "YOUR_CONSUMER_SECRET"
  config.access_token = "YOUR_ACCESS_TOKEN"
  config.access_token_secret = "YOUR_ACCESS_SECRET"
end

```

`bundle exec rails s` should now run successfully and you can now write your plugin and break things out into separate files if you’d like, but the gem dependencies should stay in the plugin.rb file.

---

<div class="post-metadata">

### Author: ![SebastianADW](https://avatars.discourse-cdn.com/v4/letter/s/7bcc69/32.png) [@SebastianADW](https://meta.discourse.org/u/SebastianADW)
#### Post date: [2018年十二月10日 21:10 UTC](https://meta.discourse.org/t/transforming-simple-ruby-files-into-a-ruby-gem/103399/5 "2018-12-10T21:10:05Z")

</div>

Thank you so much, honestly i have no clue why its working now, maybe i had a few dependencys wrong or in a wrong order, but now it works totally fine!  
A quick follow up question, what would you recommend to automize the file? So for example i want to have it run every 10 secs or something like that.

---

<div class="post-metadata">

### Author: ![SebastianADW](https://avatars.discourse-cdn.com/v4/letter/s/7bcc69/32.png) [@SebastianADW](https://meta.discourse.org/u/SebastianADW)
#### Post date: [2018年十二月14日 16:40 UTC](https://meta.discourse.org/t/transforming-simple-ruby-files-into-a-ruby-gem/103399/6 "2018-12-14T16:40:07Z")

</div>

Update:

Now i use sidekiq to run my main file.

> after\_initialize do  
> class MainPlugin  
> include Sidekiq
> 
> require\_relative File.expand\_path(‘../lib/gen\_all\_posts\_url.rb’, **FILE** )  
> require\_relative File.expand\_path(‘../lib/get\_tweets.rb’, **FILE** )  
> ##morecode
> 
> end  
> end
> 
> Sidekiq::Cron::Job.create(name: ‘MainPlugin every minute’, cron: ’ \*', class:‘MainPlugin’)

But its not working, the strange thing about it is, that i tried for class:‘plugin.rb’ once, which was obviously wrong - so i switched it back, but i am still getting the error message:

Job exception: wrong constant name plugin.rb

I dont get what i am doing wrong here
