├── CNAME ├── stylesheets ├── print.css ├── print.scss ├── application.scss ├── modules │ ├── _projects.scss │ ├── nav │ │ ├── _nav--paginated.scss │ │ └── _nav--v.scss │ ├── ie8.css │ ├── _shared.scss │ ├── _search.scss │ ├── _footer.scss │ └── _header.scss ├── _layout.scss ├── _load.scss ├── _base.scss ├── _type.scss ├── screen.scss ├── _flutie.scss └── application.css.map ├── favicon.icns ├── favicon.ico ├── fonts ├── icomoon.eot ├── icomoon.ttf └── icomoon.woff ├── .gitignore ├── images └── sponsors.png ├── _config.yml ├── .travis.yml ├── index.md ├── command-reference.erb ├── MIT-LICENSE ├── README.md ├── rdoc └── generator │ └── template │ └── jekdoc │ └── classpage.rhtml ├── credits.md ├── javascripts └── mobile-nav.js ├── name-your-gem.md ├── _plugins └── alias_generator.rb ├── what-is-a-gem.md ├── publishing.md ├── run-your-own-gem-server.md ├── resources.md ├── Rakefile ├── faqs.md ├── security.md ├── plugins.md ├── rubygems-basics.md ├── _layouts └── default.html ├── gems-with-extensions.md ├── patterns.md ├── contributing.md ├── CC-LICENSE └── make-your-own-gem.md /CNAME: -------------------------------------------------------------------------------- 1 | guides.rubygems.org 2 | -------------------------------------------------------------------------------- /stylesheets/print.css: -------------------------------------------------------------------------------- 1 | #container ul.nav { 2 | display: none; } 3 | -------------------------------------------------------------------------------- /stylesheets/print.scss: -------------------------------------------------------------------------------- 1 | #container ul.nav { 2 | display: none; 3 | } 4 | -------------------------------------------------------------------------------- /favicon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rubygems-guides/gh-pages/favicon.icns -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rubygems-guides/gh-pages/favicon.ico -------------------------------------------------------------------------------- /fonts/icomoon.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rubygems-guides/gh-pages/fonts/icomoon.eot -------------------------------------------------------------------------------- /fonts/icomoon.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rubygems-guides/gh-pages/fonts/icomoon.ttf -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | *.swp 3 | /.rvmrc 4 | /.sass-cache 5 | /_site 6 | /html 7 | /lib 8 | /tmp 9 | -------------------------------------------------------------------------------- /fonts/icomoon.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rubygems-guides/gh-pages/fonts/icomoon.woff -------------------------------------------------------------------------------- /images/sponsors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rubygems-guides/gh-pages/images/sponsors.png -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | exclude: 3 | - README.md 4 | - CNAME 5 | - vendor 6 | permalink: "pretty" 7 | safe: true 8 | markdown: kramdown 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | install: "gem install jekyll" 3 | script: "jekyll build" 4 | notifications: 5 | email: 6 | - drbrain@segment7.net 7 | -------------------------------------------------------------------------------- /stylesheets/application.scss: -------------------------------------------------------------------------------- 1 | @import "load"; 2 | @import "base"; 3 | @import "layout"; 4 | @import "type"; 5 | 6 | @import "modules/footer"; 7 | @import "modules/header"; 8 | @import "modules/projects"; 9 | @import "modules/search"; 10 | @import "modules/shared"; 11 | 12 | @import "modules/nav/nav--paginated"; 13 | @import "modules/nav/nav--v"; 14 | -------------------------------------------------------------------------------- /stylesheets/modules/_projects.scss: -------------------------------------------------------------------------------- 1 | .project__name { 2 | font: { 3 | weight: 300; 4 | size: 30px; 5 | } 6 | &:not(.is-first) { 7 | margin-top: 30px; 8 | padding-top: 22px; 9 | display: block; 10 | border-top: 1px solid lighten($gray, 13%); 11 | } 12 | } 13 | 14 | .project__links { 15 | margin: { 16 | top: 16px; 17 | bottom: 25px; 18 | } 19 | } 20 | 21 | .project__link { 22 | font: { 23 | weight: 400; 24 | size: 15px; 25 | } 26 | text-transform: uppercase; 27 | &:not(:last-child) { 28 | &:after { 29 | @extend %bullet; 30 | margin-left: 15px; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Guides 4 | previous: /credits 5 | next: /rubygems-basics 6 | --- 7 | 8 | Learn how RubyGems works, and how to make your own. 9 | 10 | The RubyGems software allows you to easily 11 | download, install, and use ruby software packages on your system. The 12 | software package is called a "gem" and contains a package Ruby 13 | application or library. 14 | 15 | Gems can be used to extend or modify 16 | functionality in Ruby applications. Commonly they're used to distribute 17 | reusable functionality that is shared with other Rubyists for use in 18 | their applications and libraries. Some gems provide command line 19 | utilities to help automate tasks and speed up your work. 20 | -------------------------------------------------------------------------------- /stylesheets/modules/nav/_nav--paginated.scss: -------------------------------------------------------------------------------- 1 | .paginated-nav-links { 2 | margin-top: 90px; 3 | padding-top: 50px; 4 | position: relative; 5 | border-top: 1px solid $gray; 6 | overflow: auto; 7 | } 8 | 9 | .paginated-nav-link--prev, .paginated-nav-link--next { 10 | color: darken($gray, 13%); 11 | @include transition-duration(.25s); 12 | @include transition-property(color); 13 | &:focus, &:hover, &.is-active { 14 | color: $black; 15 | } 16 | &:focus { 17 | outline: none; 18 | } 19 | span { 20 | position: relative; 21 | top: -1px; 22 | text-transform: uppercase; 23 | } 24 | } 25 | 26 | .paginated-nav-link--prev { 27 | float: left; 28 | span { 29 | margin-left: 5px; 30 | } 31 | } 32 | 33 | .paginated-nav-link--next { 34 | position: absolute; 35 | top: 50px; 36 | right: 0; 37 | &:before, span { 38 | float: right; 39 | } 40 | &:before { 41 | position: relative; 42 | top: 1px; 43 | } 44 | span { 45 | margin-right: 7px; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /stylesheets/modules/nav/_nav--v.scss: -------------------------------------------------------------------------------- 1 | .nav--v__link, .nav--v__link--footer { 2 | display: block; 3 | font: { 4 | weight: 800; 5 | size: 12px; 6 | } 7 | line-height: 1.66; 8 | text-transform: uppercase; 9 | @include transition-duration(.25s); 10 | @include transition-property(color); 11 | &:not(:last-child) { 12 | margin-bottom: 10px; 13 | } 14 | &.is-active { 15 | color: $red; 16 | } 17 | } 18 | 19 | .nav--v__link { 20 | padding-right: 32px; 21 | color: $black; 22 | @media (max-width: 779px) { 23 | &:last-child { 24 | margin-bottom: 60px; 25 | } 26 | } 27 | &:focus, &:hover, &:active { 28 | color: $red; 29 | } 30 | &:focus { 31 | outline: none; 32 | } 33 | } 34 | 35 | .nav--v__link--footer { 36 | color: $white; 37 | &:focus, &:hover, &:active { 38 | color: rgba($white, .3); 39 | } 40 | &:focus { 41 | outline: none; 42 | } 43 | @media (max-width: 779px) { 44 | &:last-child { 45 | margin-bottom: 36px; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /command-reference.erb: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Command Reference 4 | url: /command-reference 5 | previous: /patterns 6 | next: /rubygems-org-api 7 | --- 8 | 9 | What each `gem` command does, and how to use it. 10 | 11 | This reference was automatically generated from RubyGems version <%= rubygems_version %>. 12 | 13 | <% commands.each do |name, command| %>* [gem <%= name %>](#gem-<%= name %>) 14 | <% end %> 15 | 16 | <% commands.each do |name, command| %> 17 | ## gem <%= name %> 18 | 19 | <%= htmlify(command.summary) %> 20 | 21 | ### Usage 22 | 23 | <%= command.usage %> [options] 24 | 25 | <%= options_list(command) %> 26 | 27 | <% if command.arguments != "" %> 28 | ### Arguments 29 | 30 | <% arguments = command.arguments.split("\n") %> 31 | <% arguments.each do |argument| %><%= argument_list_item(argument) %> 32 | <% end %> 33 | <% end %> 34 | 35 | <% if command.description && command.description != "" %> 36 | ### Description 37 | 38 | <%= htmlify(command.description).gsub(/^ /, " ") %> 39 | <% end %> 40 | <% end %> 41 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, Nick Quaranto 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /stylesheets/_layout.scss: -------------------------------------------------------------------------------- 1 | %l-wrap { 2 | margin: { 3 | right: auto; 4 | left: auto; 5 | } 6 | width: 90%; 7 | } 8 | 9 | .l-overflow { 10 | overflow: auto; 11 | } 12 | 13 | .l-wrap--b { 14 | @extend %l-wrap; 15 | max-width: 940px; 16 | } 17 | 18 | .l-colspan--l, .l-colspan--r { 19 | @extend %box-sizing; 20 | @media (min-width: 780px) { 21 | width: 75%; 22 | width: calc(100% - 240px); 23 | } 24 | } 25 | 26 | .l-colspan--l { 27 | @media (min-width: 780px) { 28 | padding-right: 60px; 29 | float: left; 30 | } 31 | } 32 | 33 | .l-colspan--r { 34 | @media (min-width: 780px) { 35 | float: right; 36 | } 37 | @media (min-width: 1200px) { 38 | padding-left: 60px; 39 | } 40 | } 41 | 42 | .l-col--l, .l-col--r { 43 | @extend %box-sizing; 44 | @media (min-width: 780px) { 45 | width: 25%; 46 | width: calc(240px); 47 | } 48 | } 49 | 50 | .l-col--l { 51 | @media (max-width: 779px) { 52 | margin-bottom: 60px; 53 | } 54 | @media (min-width: 780px) { 55 | float: left; 56 | } 57 | } 58 | 59 | .l-col--l--pad { 60 | @extend .l-col--l; 61 | @media (min-width: 780px) { 62 | padding-right: 60px; 63 | } 64 | } 65 | 66 | .l-col--r { 67 | @media (min-width: 780px) { 68 | float: right; 69 | } 70 | } 71 | 72 | .l-col--r--pad { 73 | @extend .l-col--r; 74 | @media (min-width: 780px) { 75 | padding-left: 60px; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /stylesheets/modules/ie8.css: -------------------------------------------------------------------------------- 1 | // Layout 2 | 3 | .l-col--l { 4 | margin-bottom: 60px; 5 | } 6 | 7 | 8 | 9 | // Shared 10 | 11 | .main--interior { 12 | padding-bottom: 86px; 13 | } 14 | 15 | .page__heading { 16 | padding-top: 50px; 17 | padding-bottom: 16px; 18 | font-size: 48px; 19 | } 20 | 21 | 22 | 23 | // Header 24 | 25 | .l-wrap--header { 26 | margin-right: auto; 27 | margin-left: auto; 28 | position: relative; 29 | max-width: 1100px; 30 | } 31 | 32 | .header { 33 | height: 68px; 34 | } 35 | 36 | .header__logo-wrap { 37 | top: 12px; 38 | font-size: 40px; 39 | } 40 | 41 | .header__nav-links-wrap { 42 | right: 0; 43 | } 44 | 45 | 46 | 47 | // Footer 48 | 49 | .l-wrap--footer { 50 | padding-right: 5% !important; 51 | padding-left: 5% !important; 52 | } 53 | 54 | .footer__about { 55 | margin-top: 60px !important; 56 | } 57 | 58 | .footer__sponsors-wrap { 59 | margin-right: auto; 60 | margin-left: auto; 61 | padding-right: 5%; 62 | padding-left: 5%; 63 | max-width: 940px; 64 | } 65 | 66 | .footer__sponsor { 67 | margin-right: 30px; 68 | width: 100px; 69 | } 70 | 71 | 72 | 73 | // Modals 74 | 75 | body.has-modal { 76 | overflow: hidden; 77 | } 78 | 79 | .modal-wrap { 80 | &.is-showing { 81 | position: absolute; 82 | } 83 | } 84 | 85 | .modal--sign-in, .modal--sign-up { 86 | margin-left: 5%; 87 | position: absolute; 88 | top: -150%; 89 | .modal-wrap.is-showing & { 90 | top: 60px; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /stylesheets/modules/_shared.scss: -------------------------------------------------------------------------------- 1 | main, .header, .footer { 2 | @media (max-width: 1019px) { 3 | position: relative; 4 | left: 0; 5 | overflow: hidden; 6 | @include transition-duration(.25s); 7 | @include transition-property(left); 8 | &.mobile-nav-is-expanded { 9 | left: -270px; 10 | } 11 | } 12 | } 13 | 14 | main, .header { 15 | @media (max-width: 1019px) { 16 | &.mobile-nav-is-expanded { 17 | overflow: visible; 18 | } 19 | } 20 | } 21 | 22 | main { 23 | display: block; // For IE 11 24 | } 25 | 26 | .footer { 27 | @media (max-width: 1019px) { 28 | &.mobile-nav-is-expanded { 29 | overflow: hidden; 30 | } 31 | } 32 | } 33 | 34 | .main--interior { 35 | background-color: $white; 36 | @media (max-width: 929px) { 37 | padding-bottom: 86px; 38 | } 39 | @media (min-width: 930px) { 40 | padding-bottom: 175px; 41 | } 42 | } 43 | 44 | .page__heading { 45 | margin-bottom: 30px; 46 | border-bottom: 1px solid $gray; 47 | @media (max-width: 929px) { 48 | padding: { 49 | top: 18px; 50 | bottom: 10px; 51 | } 52 | } 53 | @media (min-width: 930px) { 54 | padding: { 55 | top: 30px; 56 | bottom: 30px; 57 | } 58 | } 59 | } 60 | 61 | a.page__heading { 62 | display: block; 63 | color: $black; 64 | @include transition-duration(.25s); 65 | @include transition-property(color); 66 | &:focus, &:hover, &:active { 67 | color: $red; 68 | } 69 | &:focus { 70 | outline: none; 71 | } 72 | } 73 | 74 | .colspan--l--has-border { 75 | @media (min-width: 780px) { 76 | border-right: 1px solid $gray; 77 | .footer & { 78 | border-right-color: rgba($white, .1); 79 | } 80 | } 81 | } 82 | 83 | .push { 84 | margin-top: 60px; 85 | } 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | RubyGems Guides 2 | =============== 3 | 4 | An effort to provide awesome documentation for the RubyGems ecosystem. 5 | 6 | Goals 7 | ===== 8 | 9 | * Be the definitive place for RubyGems knowledge 10 | * Help out those new to RubyGems get started and get things done 11 | * Make it easy to contribute more guides 12 | 13 | Want to help? 14 | ============= 15 | 16 | If a guide is empty, start filling it out! Or, make a new one! Pull requests 17 | are gladly accepted! 18 | 19 | * Port content from docs.rubygems.org 20 | * Port content from rubygems.org/pages/docs 21 | * Port content from help.rubygems.org knowledge base 22 | * Find lots of StackOverflow/ruby-talk questions and get their common answers in here 23 | * Fill out more guides! 24 | 25 | Setup 26 | ===== 27 | 28 | Make sure you have jekyll installed (`gem install jekyll`), and run: 29 | 30 | $ jekyll serve 31 | 32 | The pages will be available at http://localhost:4000/ 33 | 34 | Every guide except for the Command and Specification Reference is just a 35 | straight up markdown page, so just go edit it! 36 | 37 | For the Command Guide (`command-reference.md`), edit `command-reference.erb` 38 | and run: 39 | 40 | $ rake command_guide 41 | 42 | For the Specification Guide, the documentation comes directly from the 43 | `Gem::Specification` class in RubyGems. Edit it, set your `RUBYGEMS_DIR` to 44 | where your code directory is, and run: 45 | 46 | $ RUBYGEMS_DIR=~/Dev/ruby/rubygems rake spec_guide --trace 47 | 48 | Thanks 49 | ====== 50 | 51 | Huge thanks to [thoughtbot](http://thoughtbot.com) whose [handbook](http://handbook.thoughtbot.com) this is based off of. 52 | 53 | Legal 54 | ===== 55 | 56 | The actual content of the articles is licensed under Creative Commons. The code that this project consists of is licensed under MIT. 57 | -------------------------------------------------------------------------------- /stylesheets/_load.scss: -------------------------------------------------------------------------------- 1 | $red: #e9573f; 2 | $blue: #53a4e0; 3 | $green: #4fcc9c; 4 | $yellow: #ffde00; 5 | $white: #ffffff; 6 | $gray: #c1c4ca; 7 | $d-gray: #42484d; 8 | $black: #141c22; 9 | 10 | %bullet { 11 | content: ""; 12 | margin-right: 15px; 13 | position: relative; 14 | top: -2px; 15 | display: inline-block; 16 | height: 7px; 17 | width: 7px; 18 | border-radius: 4px; 19 | background-color: $gray; 20 | } 21 | 22 | %border { 23 | margin-bottom: 48px; 24 | padding-bottom: 48px; 25 | border-bottom: { 26 | style: solid; 27 | color: $gray; 28 | } 29 | } 30 | 31 | %font-smoothing { 32 | -webkit-font-smoothing: antialiased; 33 | -moz-osx-font-smoothing: grayscale; 34 | } 35 | 36 | %box-sizing { 37 | -webkit-box-sizing: border-box; 38 | -moz-box-sizing: border-box; 39 | box-sizing: border-box; 40 | } 41 | 42 | @mixin calc($property, $expression, $fallback) { 43 | #{$property}: $fallback; 44 | #{$property}: -webkit-calc(#{$expression}); 45 | #{$property}: -moz-calc(#{$expression}); 46 | #{$property}: calc(#{$expression}); 47 | } 48 | 49 | @mixin transition-duration($transition-duration) { 50 | -webkit-transition-duration: $transition-duration; 51 | -moz-transition-duration: $transition-duration; 52 | -ms-transition-duration: $transition-duration; 53 | -o-transition-duration: $transition-duration; 54 | transition-duration: $transition-duration; 55 | } 56 | 57 | @mixin transition-property($transition-property...) { 58 | -webkit-transition-property: $transition-property; 59 | -moz-transition-property: $transition-property; 60 | -ms-transition-property: $transition-property; 61 | -o-transition-property: $transition-property; 62 | transition-property: $transition-property; 63 | } 64 | 65 | @mixin transition-delay($transition-delay) { 66 | -webkit-transition-delay: $transition-delay; 67 | -moz-transition-delay: $transition-delay; 68 | -o-transition-delay: $transition-delay; 69 | transition-delay: $transition-delay; 70 | } 71 | 72 | @mixin rotate($deg) { 73 | -webkit-transform: rotateY($deg); 74 | -ms-transform: rotateY($deg); 75 | transform: rotateY($deg); 76 | } 77 | -------------------------------------------------------------------------------- /rdoc/generator/template/jekdoc/classpage.rhtml: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Specification Reference 4 | url: /specification-refence 5 | previous: /patterns 6 | next: /command-reference 7 | --- 8 | 9 | <% description = klass.description 10 | description.gsub! %r%(.*?)%m, '\2' 11 | description.gsub! %r%Specification%, 12 | 'Specification' %> 13 | <%= description %> 14 | 15 | <% 16 | sections = {} 17 | klass.each_section do |section, constants, attributes| 18 | sections[section] = attributes if section.title =~ /attributes/ 19 | end 20 | 21 | all_methods = {} 22 | sections.to_a.reverse.each do |section, attributes| 23 | all_methods[section] = {} 24 | attributes.each do |attrib| 25 | all_methods[section][attrib.name] = attrib 26 | end 27 | klass.methods_by_type(section).each do |type, visibilities| 28 | visibilities.each do |visibility, methods| 29 | methods.each do |method| 30 | all_methods[section][method.name] = method 31 | end 32 | end 33 | end 34 | end 35 | %> 36 | 37 | <% all_methods.each do |section, methods| %> 38 | ## <%= section.title %> 39 | <% methods.sort_by(&:first).each do |name, method| %> 40 | * [<%= name %>](#<%= name %>) 41 | <% end %> 42 | <% end %> 43 | 44 | <% all_methods.each do |section, methods| %> 45 | 46 | # <%= section.title %> 47 | 48 | <% methods.sort_by(&:first).each do |name, method| 49 | params = 50 | if method.params then 51 | params = method.params.delete '()' 52 | 53 | if params.empty? then 54 | '' 55 | else 56 | params = params.split(',').map { |param| "`#{param.strip}`" }.join ', ' 57 | "(#{params})" 58 | end 59 | end 60 | %> 61 | 62 | 63 | 64 | ## <%= name %><%= params %> 65 | <% description = method.description.strip 66 | description.gsub! %r%(.*?)%m, '\2' 67 | description.gsub! %r%Specification%, 68 | 'Specification' %> 69 | <%= description %> 70 | <% end %> 71 | <% end %> 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /credits.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Credits 4 | previous: /plugins 5 | next: / 6 | --- 7 | 8 | This site is [open source](https://github.com/rubygems/guides) and its content is 9 | [Creative Commons](https://github.com/rubygems/guides/blob/gh-pages/CC-LICENSE) 10 | licensed. 11 | 12 | Contributors 13 | ------------ 14 | 15 | These people have donated time to creating and improving the RubyGems Guides site: 16 | 17 | * [Gabe Berke-Williams](https://github.com/gabebw) 18 | * [Gregory Brown](https://github.com/sandal) 19 | * [Amaia Castro](https://github.com/amaia) 20 | * [Ryan Davis](https://github.com/zenspider) 21 | * [Vijay Dev](https://github.com/vijaydev) 22 | * [Evgene Dzhelyov](https://github.com/edzhelyov) 23 | * [Mike Gunderloy](https://github.com/ffmike) 24 | * [Gabriel Horner](https://github.com/cldwalker) 25 | * [Richard Michael](https://github.com/richardkmichael) 26 | * [John Lees-Miller](https://github.com/jdleesmiller) 27 | * [Mark McSpadden](https://github.com/markmcspadden) 28 | * [Erik Michaels-Ober](https://github.com/sferik) 29 | * [Scott Moak](https://github.com/smoak) 30 | * [Jason Morrison](https://github.com/jasonm) 31 | * [Ryan Neufeld](https://github.com/rkneufeld) 32 | * [Nick Quaranto](https://github.com/qrush) 33 | * [Sebastian Spier](https://github.com/spier) 34 | * [Antonio Terceiro](https://github.com/terceiro) 35 | * [thrackle](https://github.com/thrackle) 36 | 37 | Acknowledgments 38 | --------------- 39 | 40 | Material for the Guides was adapted from these sources: 41 | 42 | * [Gem Packaging: Best Practices](http://weblog.rubyonrails.org/2009/9/1/gem-packaging-best-practices) 43 | * [Gem Sawyer, Modern Day Ruby Warrior](http://rubylearning.com/blog/2010/10/06/gem-sawyer-modern-day-ruby-warrior/) 44 | * [How to Name Gems](http://blog.segment7.net/2010/11/15/how-to-name-gems) 45 | * [Rubygems Good Practice](http://yehudakatz.com/2009/07/24/rubygems-good-practice/) 46 | * [Writing Ruby C extensions: Part 1](http://tenderlovemaking.com/2009/12/18/writing-ruby-c-extensions-part-1) 47 | * [Writing Ruby C extensions: Part 2](http://tenderlovemaking.com/2010/12/11/writing-ruby-c-extensions-part-2) 48 | 49 | Hosting 50 | ------- 51 | 52 | Hosted by [GitHub Pages](http://pages.github.com/). 53 | -------------------------------------------------------------------------------- /javascripts/mobile-nav.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | // cache jQuery lookups into variables 3 | // so we don't have to traverse the DOM every time 4 | var sandwichIcon = $('.header__club-sandwich'); 5 | var header = $('.header'); 6 | var main = $('main'); 7 | var footer = $('.footer'); 8 | var signUpLink = $('.header__nav-link.js-sign-up-trigger'); 9 | var signInLink = $('.hader__nav-link.js-sign-in-trigger'); 10 | var navExpandedClass = 'mobile-nav-is-expanded'; 11 | var headerSeach = $('.header__search'); 12 | var headerLogo = $('.header__logo-wrap'); 13 | 14 | // variable to support mobile nav tab behaviour 15 | // * skipSandwichIcon is for skipping sandwich icon 16 | // when you tab from "gem" icon 17 | // * tabDirection is for hiding and showing navbar 18 | // when you tab in and out 19 | var skipSandwichIcon = true; 20 | var tabDirection = true; 21 | 22 | function removeNavExpandedClass() { 23 | header.removeClass(navExpandedClass); 24 | main.removeClass(navExpandedClass); 25 | footer.removeClass(navExpandedClass); 26 | } 27 | 28 | function addNavExpandedClass() { 29 | header.addClass(navExpandedClass); 30 | main.addClass(navExpandedClass); 31 | footer.addClass(navExpandedClass); 32 | } 33 | 34 | function handleClick(event) { 35 | var isMobileNavExpanded = header.hasClass(navExpandedClass); 36 | 37 | event.preventDefault(); 38 | 39 | if (isMobileNavExpanded) { 40 | removeNavExpandedClass(); 41 | } else { 42 | addNavExpandedClass(); 43 | } 44 | } 45 | 46 | function handleFocusIn() { 47 | if (skipSandwichIcon) { 48 | addNavExpandedClass(); 49 | headerSeach.focus(); 50 | skipSandwichIcon = false; 51 | } else { 52 | removeNavExpandedClass(); 53 | headerLogo.focus(); 54 | skipSandwichIcon = true; 55 | } 56 | } 57 | 58 | sandwichIcon.click(handleClick); 59 | 60 | sandwichIcon.on('focusin', handleFocusIn); 61 | 62 | signUpLink.on('focusin', function() { 63 | if (!tabDirection) { 64 | addNavExpandedClass(); 65 | } 66 | }); 67 | 68 | signUpLink.on('focusout', function() { 69 | if (tabDirection) { 70 | tabDirection = false; 71 | removeNavExpandedClass(); 72 | } else { 73 | tabDirection = true; 74 | addNavExpandedClass(); 75 | } 76 | }); 77 | }); 78 | -------------------------------------------------------------------------------- /stylesheets/_base.scss: -------------------------------------------------------------------------------- 1 | html, body, div, span, applet, object, iframe, 2 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 3 | a, abbr, acronym, address, big, cite, code, 4 | del, dfn, em, img, ins, kbd, q, s, samp, 5 | small, strike, strong, sub, sup, tt, var, 6 | b, u, i, center, 7 | dl, dt, dd, ol, ul, li, 8 | fieldset, form, label, legend, 9 | table, caption, tbody, tfoot, thead, tr, th, td, 10 | article, aside, canvas, details, embed, 11 | figure, figcaption, footer, header, hgroup, 12 | menu, nav, output, ruby, section, summary, 13 | time, mark, audio, video { 14 | margin: 0; 15 | padding: 0; 16 | border: 0; 17 | } 18 | 19 | article, aside, details, figcaption, figure, 20 | footer, header, hgroup, menu, nav, section { 21 | display: block; 22 | } 23 | 24 | body { 25 | background-color: $red; 26 | font: { 27 | family: "aktiv-grotesk-std", sans-serif; 28 | size: 15px; 29 | } 30 | } 31 | 32 | section, article { 33 | &:not(:last-of-type) { 34 | @extend %border; 35 | } 36 | } 37 | 38 | section { 39 | &:not(:last-of-type) { 40 | border-bottom-width: 5px; 41 | } 42 | } 43 | 44 | article { 45 | &:not(:last-of-type) { 46 | border-bottom-width: 1px; 47 | } 48 | } 49 | 50 | i, em { 51 | font-style: italic; 52 | } 53 | 54 | b, strong { 55 | font-weight: 800; 56 | } 57 | 58 | a { 59 | text-decoration: none; 60 | } 61 | 62 | li { 63 | list-style-type: none; 64 | } 65 | 66 | pre { 67 | overflow: scroll; 68 | overflow: auto\0; 69 | background-color: $black; 70 | code { 71 | @extend %font-smoothing; 72 | color: $white; 73 | } 74 | } 75 | 76 | @font-face { 77 | font: { 78 | family: "icomoon"; 79 | weight: normal; 80 | style: normal; 81 | } 82 | src: url("/fonts/icomoon.eot"); 83 | src: url("/fonts/icomoon.eot?#iefix") format("eot"), url("/fonts/icomoon.woff") format("woff"), url("/fonts/icomoon.ttf") format("truetype"); 84 | } 85 | 86 | [data-icon]:before { 87 | content: attr(data-icon); 88 | font-family: "icomoon"; 89 | @extend %font-smoothing; 90 | speak: none; 91 | } 92 | 93 | ::-webkit-input-placeholder { 94 | font-style: italic; 95 | } 96 | 97 | :-moz-placeholder { 98 | font-style: italic; 99 | } 100 | 101 | ::-moz-placeholder { 102 | font-style: italic; 103 | } 104 | 105 | :-ms-input-placeholder { 106 | font-style: italic; 107 | } 108 | -------------------------------------------------------------------------------- /stylesheets/modules/_search.scss: -------------------------------------------------------------------------------- 1 | %search__icon { 2 | position: absolute; 3 | cursor: pointer; 4 | } 5 | 6 | %search { 7 | -webkit-appearance: none; 8 | padding: 10px; 9 | background-color: $white; 10 | border: none; 11 | border-radius: 5px; 12 | font: { 13 | weight: 300; 14 | family: "aktiv-grotesk-std", sans-serif; 15 | } 16 | color: $black; 17 | outline: none; 18 | &::-webkit-input-placeholder { 19 | color: $red; 20 | } 21 | &:-moz-placeholder { 22 | color: $red; 23 | } 24 | &::-moz-placeholder { 25 | color: $red; 26 | } 27 | &:-ms-input-placeholder { 28 | color: $red; 29 | } 30 | } 31 | 32 | .header__search-wrap { 33 | position: relative; 34 | @extend %box-sizing; 35 | @media (max-width: 1019px) { 36 | margin-top: 8px; 37 | padding: { 38 | right: 10px; 39 | bottom: 8px; 40 | left: 16px; 41 | } 42 | @-moz-document url-prefix() { 43 | margin-top: 7px; 44 | padding-bottom: 6px; 45 | } 46 | } 47 | @media (min-width: 1020px) { 48 | margin: { 49 | top: 18px; 50 | right: 16px; 51 | left: 80px; 52 | } 53 | float: left; 54 | } 55 | @media (min-width: 1020px) and (max-width: 1139px) { 56 | width: 260px; 57 | } 58 | @media (min-width: 1140px) { 59 | width: 360px; 60 | } 61 | } 62 | 63 | .header__search-wrap--home { 64 | @extend .header__search-wrap; 65 | @media (min-width: 1020px) { 66 | display: none; 67 | } 68 | } 69 | 70 | .header__search__icon { 71 | @extend %search__icon; 72 | top: 6px; 73 | right: 5px; 74 | border: none; 75 | background-color: transparent; 76 | font: { 77 | size: 16px; 78 | family: "icomoon"; 79 | } 80 | color: $red; 81 | @include transition-duration(.25s); 82 | @include transition-property(color); 83 | @media (max-width: 1019px) { 84 | right: 15px; 85 | } 86 | &:hover, &:focus { 87 | color: #fa3c29; 88 | outline: none; 89 | } 90 | } 91 | 92 | .header__search { 93 | @extend %search; 94 | @extend %box-sizing; 95 | padding: 8px 32px 8px 8px; 96 | width: 100%; 97 | box-shadow: 0 0 0px 3px rgba($black, .1); 98 | font-size: 15px; 99 | &::-webkit-input-placeholder { 100 | opacity: 1; 101 | color: $red; 102 | } 103 | &:-moz-placeholder { 104 | opacity: 1; 105 | color: $red; 106 | } 107 | &::-moz-placeholder { 108 | opacity: 1; 109 | color: $red; 110 | } 111 | &:-ms-input-placeholder { 112 | opacity: 1; 113 | color: $red; 114 | } 115 | &:hover, &:focus { 116 | & ~ .header__search__icon { 117 | color: $red; 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /name-your-gem.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Name your gem 4 | url: /name-your-gem 5 | previous: /gems-with-extensions 6 | next: /publishing 7 | --- 8 | 9 | Our recommendation on the use of "_" and "-" in your gem's name. 10 | 11 | Here are some examples of our recommendations for naming gems: 12 | 13 | Gem name | Require statement | Main class or module 14 | ---------------------- | -------------------------------- | ----------------------- 15 | `ruby_parser` | `require 'ruby_parser'` | `RubyParser` 16 | `rdoc-data` | `require 'rdoc/data'` | `RDoc::Data` 17 | `net-http-persistent` | `require 'net/http/persistent'` | `Net::HTTP::Persistent` 18 | `net-http-digest_auth` | `require 'net/http/digest_auth'` | `Net::HTTP::DigestAuth` 19 | 20 | The main goal of these recommendations is to give the user some clue about 21 | how to require the files in your gem. Following these conventions also lets 22 | Bundler require your gem with no extra configuration. 23 | 24 | If you publish a gem on [rubygems.org][rubygems] it may be removed if the name 25 | is objectionable, violates intellectual property or the contents of the gem 26 | meet these criteria. You can report such a gem on the 27 | [RubyGems Support][rubygems-support] site. 28 | 29 | [rubygems]: http://rubygems.org 30 | [rubygems-support]: http://help.rubygems.org 31 | 32 | Use underscores for multiple words 33 | ---------------------------------- 34 | 35 | If a class or module has multiple words, use underscores to separate them. This 36 | matches the file the user will require, making it easier for the user to start 37 | using your gem. 38 | 39 | Use dashes for extensions 40 | ------------------------- 41 | 42 | If you're adding functionality to another gem, use a dash. This usually 43 | corresponds to a `/` in the require statement (and therefore your gem's 44 | directory structure) and a `::` in the name of your main class or module. 45 | 46 | Mix underscores and dashes appropriately 47 | ---------------------------------------- 48 | 49 | If your class or module has multiple words and you're also adding functionality 50 | to another gem, follow both of the rules above. For example, 51 | [`net-http-digest_auth`][digest-gem] adds 52 | [HTTP digest authentication][digest-standard] to `net/http`. 53 | The user will `require 'net/http/digest_auth'` to use the extension 54 | (in class `Net::HTTP::DigestAuth`). 55 | 56 | [digest-gem]: https://rubygems.org/gems/net-http-digest_auth 57 | [digest-standard]: http://tools.ietf.org/html/rfc2617 58 | 59 | Don't use UPPERCASE letters 60 | --------------------------- 61 | 62 | OS X and Windows have case-insensitive filesystems by default. Users may 63 | mistakenly require files from a gem using uppercase letters which will be 64 | non-portable if they move it to a non-windows or OS X system. While this will 65 | mostly be a newbie mistake we don't need to be confusing them more than 66 | necessary. 67 | 68 | Credits 69 | ------- 70 | 71 | This guide was expanded from [How to Name Gems][how-to-name-gems] by Eric Hodel. 72 | 73 | [how-to-name-gems]: https://web.archive.org/web/20130821183311/http://blog.segment7.net/2010/11/15/how-to-name-gems 74 | -------------------------------------------------------------------------------- /_plugins/alias_generator.rb: -------------------------------------------------------------------------------- 1 | # Alias Generator for Posts. 2 | # 3 | # Generates redirect pages for posts with aliases set in the YAML Front Matter. 4 | # 5 | # Place the full path of the alias (place to redirect from) inside the 6 | # destination post's YAML Front Matter. One or more aliases may be given. 7 | # 8 | # Example Post Configuration: 9 | # 10 | # --- 11 | # layout: post 12 | # title: "How I Keep Limited Pressing Running" 13 | # alias: /post/6301645915/how-i-keep-limited-pressing-running/index.html 14 | # --- 15 | # 16 | # Example Post Configuration: 17 | # 18 | # --- 19 | # layout: post 20 | # title: "How I Keep Limited Pressing Running" 21 | # alias: [/first-alias/index.html, /second-alias/index.html] 22 | # --- 23 | # 24 | # Author: Thomas Mango 25 | # Site: http://thomasmango.com 26 | # Plugin Source: http://github.com/tsmango/jekyll_alias_generator 27 | # Site Source: http://github.com/tsmango/thomasmango.com 28 | # PLugin License: MIT 29 | 30 | module Jekyll 31 | 32 | class AliasGenerator < Generator 33 | 34 | def generate(site) 35 | @site = site 36 | 37 | process_posts 38 | process_pages 39 | end 40 | 41 | def process_posts 42 | @site.posts.each do |post| 43 | generate_aliases(post.url, post.data['alias']) 44 | end 45 | end 46 | 47 | def process_pages 48 | @site.pages.each do |page| 49 | generate_aliases(page.destination('').gsub(/index\.(html|htm)$/, ''), page.data['alias']) 50 | end 51 | end 52 | 53 | def generate_aliases(destination_path, aliases) 54 | alias_paths ||= Array.new 55 | alias_paths << aliases 56 | alias_paths.compact! 57 | 58 | alias_paths.flatten.each do |alias_path| 59 | alias_path = alias_path.to_s 60 | 61 | alias_dir = File.extname(alias_path).empty? ? alias_path : File.dirname(alias_path) 62 | alias_file = File.extname(alias_path).empty? ? "index.html" : File.basename(alias_path) 63 | 64 | fs_path_to_dir = File.join(@site.dest, alias_dir) 65 | alias_index_path = File.join(alias_dir, alias_file) 66 | 67 | FileUtils.mkdir_p(fs_path_to_dir) 68 | 69 | File.open(File.join(fs_path_to_dir, alias_file), 'w') do |file| 70 | file.write(alias_template(destination_path)) 71 | end 72 | 73 | (alias_index_path.split('/').size + 1).times do |sections| 74 | @site.static_files << Jekyll::AliasFile.new(@site, @site.dest, alias_index_path.split('/')[0, sections].join('/'), '') 75 | end 76 | end 77 | end 78 | 79 | def alias_template(destination_path) 80 | <<-EOF 81 | 82 | 83 |
84 | 85 | 86 | 87 | 88 | 89 | EOF 90 | end 91 | end 92 | 93 | class AliasFile < StaticFile 94 | require 'set' 95 | 96 | def destination(dest) 97 | File.join(dest, @dir) 98 | end 99 | 100 | def modified? 101 | return false 102 | end 103 | 104 | def write(dest) 105 | return true 106 | end 107 | end 108 | end -------------------------------------------------------------------------------- /stylesheets/modules/_footer.scss: -------------------------------------------------------------------------------- 1 | .footer { 2 | padding: { 3 | top: 48px; 4 | bottom: 48px; 5 | } 6 | position: relative; 7 | overflow: auto; 8 | border-top: 1px solid rgba($white, .3); 9 | background-color: $black; 10 | box-shadow: 0 -4px 0 0 $black; 11 | z-index: 2; 12 | @media (min-width: 780px) { 13 | min-height: 70vh; 14 | } 15 | } 16 | 17 | .l-wrap--footer { 18 | margin: { 19 | right: auto; 20 | left: auto; 21 | } 22 | max-width: 940px; 23 | @media (max-width: 579px) { 24 | width: 78%; 25 | } 26 | @media (min-width: 580px) { 27 | width: 90%; 28 | } 29 | } 30 | 31 | .footer__about { 32 | max-width: 550px; 33 | font-weight: 300; 34 | line-height: 1.66; 35 | color: lighten($d-gray, 18%); 36 | @media (max-width: 579px) { 37 | font-size: 15px; 38 | } 39 | @media (min-width: 580px) { 40 | font-size: 18px; 41 | } 42 | @media (min-width: 780px) { 43 | min-height: 222px; 44 | } 45 | } 46 | 47 | .footer__sponsors-wrap { 48 | margin-top: 60px; 49 | padding-top: 45px; 50 | border-top: 1px solid rgba($white, .1); 51 | @media (min-width: 1040px) { 52 | margin: { 53 | right: auto; 54 | left: auto; 55 | } 56 | max-width: 940px; 57 | } 58 | } 59 | 60 | .footer__sponsors { 61 | margin: { 62 | right: auto; 63 | left: auto; 64 | } 65 | @media (max-width: 579px) { 66 | width: 78%; 67 | } 68 | @media (min-width: 580px) and (max-width: 1039px) { 69 | width: 90%; 70 | } 71 | } 72 | 73 | .footer__sponsor { 74 | margin-bottom: 36px; 75 | float: left; 76 | height: 100px; 77 | background: { 78 | image: url(/images/sponsors.png); 79 | size: 100%; 80 | } 81 | font: { 82 | style: italic; 83 | weight: 300; 84 | size: 12px; 85 | } 86 | text-align: center; 87 | color: $white; 88 | opacity: .4; 89 | @include transition-duration(.25s); 90 | @include transition-property(opacity); 91 | &:focus, &:hover { 92 | opacity: 1; 93 | } 94 | &:focus { 95 | outline: none; 96 | } 97 | &:nth-child(1) { 98 | background-position: 0 20px; 99 | } 100 | @media (max-width: 579px) { 101 | &:nth-child(odd) { 102 | margin-right: 18%; 103 | } 104 | } 105 | @media (min-width: 580px) { 106 | &:not(:last-child) { 107 | margin-right: 30px; 108 | } 109 | } 110 | @media (max-width: 1039px) { 111 | width: 100px; 112 | &:nth-child(2) { 113 | background-position: 0 -84px; 114 | } 115 | &:nth-child(3) { 116 | background-position: 0 -174px; 117 | } 118 | &:nth-child(4) { 119 | background-position: 0 -264px; 120 | } 121 | &:nth-child(5) { 122 | background-position: 0 -355px; 123 | } 124 | &:nth-child(6) { 125 | background-position: 0 108px; 126 | } 127 | &:nth-child(7) { 128 | background-position: 0 -456px; 129 | } 130 | &:nth-child(8) { 131 | background-position: 0 210px; 132 | } 133 | } 134 | @media (min-width: 1040px) { 135 | width: 90px; 136 | &:nth-child(2) { 137 | background-position: 0 -72px; 138 | } 139 | &:nth-child(3) { 140 | background-position: 0 -153px; 141 | } 142 | &:nth-child(4) { 143 | background-position: 0 -236px; 144 | } 145 | &:nth-child(5) { 146 | background-position: 0 -314px; 147 | } 148 | &:nth-child(6) { 149 | background-position: 0 100px; 150 | } 151 | &:nth-child(7) { 152 | background-position: 0 -409px; 153 | } 154 | &:nth-child(8) { 155 | background-position: 0 192px; 156 | } 157 | } 158 | } 159 | 160 | .footer__sponsor__logo { 161 | margin-top: 5px; 162 | width: 100%; 163 | } 164 | -------------------------------------------------------------------------------- /what-is-a-gem.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: What is a gem? 4 | url: /what-is-a-gem 5 | previous: /rubygems-basics 6 | next: /make-your-own-gem 7 | --- 8 | 9 | Unpack the mystery behind what's in a RubyGem. 10 | 11 | Structure of a Gem 12 | ------------------ 13 | 14 | Each gem has a name, version, and platform. For example, the 15 | [rake](http://rubygems.org/gems/rake) gem has a `0.8.7` version (from May, 16 | 2009). Rake's platform is `ruby`, which means it works on any platform Ruby 17 | runs on. 18 | 19 | Platforms are based on the CPU architecture, operating system type and 20 | sometimes the operating system version. Examples include "x86-mingw32" or 21 | "java". The platform indicates the gem only works with a ruby built for the 22 | same platform. RubyGems will automatically download the correct version for 23 | your platform. See `gem help platform` for full details. 24 | 25 | Inside a gems are the following components: 26 | 27 | * Code (including tests and supporting utilities) 28 | * Documentation 29 | * gemspec 30 | 31 | Each gem follows the same standard structure of code organization: 32 | 33 | % tree freewill 34 | freewill/ 35 | ├── bin/ 36 | │ └── freewill 37 | ├── lib/ 38 | │ └── freewill.rb 39 | ├── test/ 40 | │ └── test_freewill.rb 41 | ├── README 42 | ├── Rakefile 43 | └── freewill.gemspec 44 | 45 | Here, you can see the major components of a gem: 46 | 47 | * The `lib` directory contains the code for the gem 48 | * The `test` or `spec` directory contains tests, depending on which test 49 | framework the developer uses 50 | * A gem usually has a `Rakefile`, which the 51 | [rake](http://rake.rubyforge.org/) program uses to automate tests, 52 | generate code, and perform other tasks. 53 | * This gem also includes an executable file in the 54 | `bin` directory, which will be loaded into the user's `PATH` when the gem is 55 | installed. 56 | * Documentation is usually included in the `README` and inline with the code. 57 | When you install a gem, documentation is generated automatically for you. 58 | Most gems include [RDoc](http://rdoc.sourceforge.net/doc/) documentation, 59 | but some use [YARD](http://yardoc.org/) docs instead. 60 | * The final piece is the gemspec, which contains information about the gem. 61 | The gem's files, test information, platform, version number and more are all 62 | laid out here along with the author's email and name. 63 | 64 | [More information on the gemspec file](/specification-reference/) 65 | 66 | [Building your own gem](/make-your-own-gem/) 67 | 68 | The Gemspec 69 | ----------- 70 | 71 | Your application, your gem's users, and you 6 months from now will want to 72 | know who wrote a gem, when, and what it does. The gemspec contains this 73 | information. 74 | 75 | Here's an example of a gemspec file. You can learn more in [how to make a 76 | gem](/make-your-own-gem). 77 | 78 | % cat freewill.gemspec 79 | Gem::Specification.new do |s| 80 | s.name = 'freewill' 81 | s.version = '1.0.0' 82 | s.summary = "Freewill!" 83 | s.description = "I will choose Freewill!" 84 | s.authors = ["Nick Quaranto"] 85 | s.email = 'nick@quaran.to' 86 | s.homepage = 'http://example.com/freewill' 87 | s.files = ["lib/freewill.rb", ...] 88 | end 89 | 90 | For more information on the gemspec, please check out the full [Specification 91 | Reference](/specification-reference) which goes over each metadata field in 92 | detail. 93 | 94 | Credits 95 | ------- 96 | 97 | This guide was adapted from [Gonçalo 98 | Silva](https://twitter.com/#!/goncalossilva)'s original tutorial on 99 | docs.rubygems.org and from Gem Sawyer, Modern Day Ruby Warrior. 100 | -------------------------------------------------------------------------------- /publishing.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Publishing your gem 4 | url: /publishing 5 | previous: /name-your-gem 6 | next: /security 7 | --- 8 | 9 | Start with an idea, end with a distributable package of Ruby code. 10 | 11 | Ways to share your gem code with other users. 12 | 13 | * [Introduction](#introduction) 14 | * [Sharing Source Code](#sharing-source-code) 15 | * [Serving Your Own Gems](#serving-your-own-gems) 16 | * [Publishing to RubyGems.org](#publishing-to-rubygemsorg) 17 | * [Push Permissions on RubyGems.org](#push-permissions-on-rubygemsorg) 18 | * [Gem Security](#gem-security) 19 | 20 | Introduction 21 | ------------ 22 | 23 | Now that you've [created your gem](/make-your-own-gem), you're probably ready 24 | to share it. While it is perfectly reasonable to create private gems solely to 25 | organize the code in large private projects, it's more common to build gems so 26 | that they can be used by multiple projects. This guide discusses the various 27 | ways that you can share your gem with the world. 28 | 29 | Sharing Source Code 30 | ------------------- 31 | 32 | The simplest way (from the author's perspective) to share a gem for other 33 | developers' use is to distribute it in source code form. If you place the full 34 | source code for your gem on a public git repository (often, though not always, 35 | this means sharing it via [GitHub](https://github.com)), then other users can 36 | install it with [Bundler's git functionality](http://bundler.io/git.html). 37 | 38 | For example, you can install the latest code for the wicked_pdf gem in a 39 | project by including this line in your Gemfile: 40 | 41 | gem "wicked_pdf", :git => "git://github.com/mileszs/wicked_pdf.git" 42 | 43 | > Installing a gem directly from a git repository is a feature of Bundler, not 44 | > a feature of RubyGems. Gems installed this way will not show up when you run 45 | > `gem list`. 46 | 47 | Serving Your Own Gems 48 | --------------------- 49 | 50 | If you want to control who can install a gem, or directly track the activity 51 | surrounding a gem, then you'll want to set up a private gem server. You can 52 | [set up your own gem server](/run-your-own-gem-server) or use a commercial 53 | service such as [Gemfury](http://www.gemfury.com/). 54 | 55 | RubyGems 2.2.0 and newer support the `allowed_push_host` metadata value to 56 | restrict gem pushes to a single host. If you are publishing private gems you 57 | should set this value to prevent accidental pushes to rubygems.org: 58 | 59 | Gem::Specification.new 'my_gem', '1.0' do |s| 60 | # ... 61 | s.metadata['allowed_push_host'] = 'https://gems.my-company.example' 62 | end 63 | 64 | See the [Resources](/resources) guide for an up-to-date listing of options for 65 | private gem servers. 66 | 67 | Publishing to RubyGems.org 68 | -------------------------- 69 | 70 | The simplest way to distribute a gem for public consumption is to use 71 | [RubyGems.org](https://rubygems.org/). Gems that are published to RubyGems.org 72 | can be installed via the `gem install` command or through the use of tools such 73 | as Isolate or Bundler. 74 | 75 | To begin, you'll need to create an account on RubyGems.org. Visit the [sign 76 | up](https://rubygems.org/users/new) page and supply an email address that you 77 | control, a handle (username) and a password. 78 | 79 | After creating the account, use your email and password when pushing the gem. 80 | (RubyGems saves the credentials in ~/.gem/credentials for you so you only need 81 | to log in once.) 82 | 83 | To publish version 0.1.0 of a new gem named 'squid-utils': 84 | 85 | $ gem push squid-utils-0.1.0.gem 86 | Enter your RubyGems.org credentials. 87 | Don't have an account yet? Create one at https://rubygems.org/sign_up 88 | Email: gem_author@example 89 | Password: 90 | Signed in. 91 | Pushing gem to RubyGems.org... 92 | Successfully registered gem: squid-utils (0.1.0) 93 | 94 | Congratulations! Your new gem is now ready for any ruby user in the world to 95 | install! 96 | 97 | Push Permissions on RubyGems.org 98 | -------------------------------- 99 | 100 | If you have multiple maintainers for your gem you can give your fellow 101 | maintainers permission to push the gem to rubygems.org through the [gem 102 | owner command](/command-reference/#gem_owner). 103 | 104 | Gem Security 105 | ------------ 106 | 107 | See [Security](/security) page. 108 | -------------------------------------------------------------------------------- /run-your-own-gem-server.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Run your own gem server 4 | url: /run-your-own-gem-server 5 | previous: /rubygems-org-api 6 | next: /resources 7 | --- 8 | 9 | Need to serve gems locally or for your organization? 10 | 11 | There are times you would like to run your own gem server. You may want to 12 | share gems with colleagues when you are both without internet connectivity. You 13 | may have private code, internal to your organization, that you'd like to 14 | distribute and manage as gems without making the source publicly available. 15 | 16 | There are a few options to set up a server to host gems from within your 17 | organization. This guide covers the `gem server` command and the [Gem in a 18 | Box](https://github.com/geminabox/geminabox) project. It also discusses how to 19 | use these servers as gem sources during development. 20 | 21 | ## Running the built-in gem server 22 | 23 | When you install RubyGems, it adds the `gem server` command to your system. 24 | This is the fastest way to start hosting gems. Just run the command: 25 | 26 | gem server 27 | 28 | This will serve all your installed gems from your local machine at 29 | [http://localhost:8808](http://localhost:8808). If you visit this url in your 30 | browser, you'll find that the `gem server` command provides an HTML 31 | documentation index. 32 | 33 | When you install new gems, they are automatically available through the 34 | built-in gem server. 35 | 36 | For a complete list of options, run: 37 | 38 | gem server --help 39 | 40 | Among other options, you can change the port that gems are served on and 41 | specify the directories to search for installed gems. 42 | 43 | ## Running Gem in a Box 44 | 45 | For a server with more features, including the ability to push gems, try out 46 | the [Gem in a Box](https://github.com/geminabox/geminabox) project. 47 | 48 | To get started, install `geminabox`: 49 | 50 | [~/dev/geminabox] gem install geminabox 51 | 52 | Make a data directory for storing gems: 53 | 54 | [~/dev/geminabox] mkdir data 55 | 56 | Include the following in a `config.ru` file: 57 | 58 | [~/dev/geminabox] cat config.ru 59 | require "rubygems" 60 | require "geminabox" 61 | 62 | Geminabox.data = "./data" 63 | run Geminabox::Server 64 | 65 | And run the server: 66 | 67 | [~/dev/geminabox] rackup 68 | [2011-05-19 12:09:40] INFO WEBrick 1.3.1 69 | [2011-05-19 12:09:40] INFO ruby 1.9.2 (2011-02-18) [x86_64-darwin10.5.0] 70 | [2011-05-19 12:09:40] INFO WEBrick::HTTPServer#start: pid=60941 port=9292 71 | 72 | Now you can push gems using the `gem inabox` command. The first time you do 73 | this, you'll be prompted for the location of your gem server. 74 | 75 | [~/dev/secretgem] gem build secretgem.gemspec 76 | Successfully built RubyGem 77 | Name: secretgem 78 | Version: 0.0.1 79 | File: secretgem-0.0.1.gem 80 | [~/dev/secretgem] gem inabox ./secretgem-0.0.1.gem 81 | Enter the root url for your personal geminabox instance. (E.g. http://gems/) 82 | Host: http://localhost:9292 83 | Pushing secretgem-0.0.1.gem to http://localhost:9292/... 84 | 85 | There is a web interface available on 86 | [http://localhost:9292](http://localhost:9292) as well. For more information, 87 | read the [Gem in a box](https://github.com/geminabox/geminabox) README. 88 | 89 | ## Using gems from your server 90 | 91 | Whether you use `gem server`, Gem in a Box, or another gem server, you can 92 | configure RubyGems to use your local or internal source alongside other sources 93 | such as [http://rubygems.org](http://rubygems.org). 94 | 95 | Use the `gem sources` command to add the gem server to your system-wide gem 96 | sources. The following URL is the default for running Gem in a Box via 97 | `rackup`: 98 | 99 | gem sources --add http://localhost:9292 100 | 101 | Then install gems as usual: 102 | 103 | [~] gem install secretgem 104 | Successfully installed secretgem-0.0.1 105 | 1 gem installed 106 | 107 | If you're using [Bundler](http://bundler.io) then you can specify this 108 | server as a gem source in your `Gemfile`: 109 | 110 | [~/dev/myapp] cat Gemfile 111 | source "http://localhost:9292" 112 | gem "secretgem" 113 | 114 | [~/dev/myapp] bundle 115 | Using secretgem (0.0.1) 116 | Using bundler (1.0.13) 117 | Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed. 118 | -------------------------------------------------------------------------------- /stylesheets/_type.scss: -------------------------------------------------------------------------------- 1 | .t-display { 2 | font-weight: 200; 3 | @media (max-width: 929px) { 4 | font-size: 30px; 5 | } 6 | @media (min-width: 930px) { 7 | font-size: 60px; 8 | } 9 | } 10 | 11 | .t-hidden { 12 | position: absolute !important; 13 | height: 1px; 14 | width: 1px; 15 | overflow: hidden; 16 | clip: rect(1px 1px 1px 1px); 17 | clip: rect(1px, 1px, 1px, 1px); 18 | } 19 | 20 | .t-gray { 21 | color: darken($gray, 13%); 22 | } 23 | 24 | .t-uppercase { 25 | text-transform: uppercase; 26 | } 27 | 28 | 29 | 30 | // Links 31 | 32 | .t-link { 33 | color: $red; 34 | @include transition-duration(.25s); 35 | @include transition-property(color); 36 | &:focus, &:hover, &:active { 37 | color: rgba($red, .7); 38 | } 39 | &:focus { 40 | outline: none; 41 | } 42 | } 43 | 44 | 45 | 46 | // Body 47 | 48 | .t-body { 49 | p, ol li, ul li { 50 | font: { 51 | weight: 300; 52 | size: 18px; 53 | } 54 | line-height: 1.66; 55 | } 56 | 57 | p, ul, ol, pre, table { 58 | margin-bottom: 30px; 59 | } 60 | 61 | a { 62 | @extend .t-link; 63 | word-wrap: break-word; 64 | } 65 | 66 | b, strong { 67 | font-weight: 500; 68 | } 69 | 70 | h1, h2 { 71 | margin-bottom: 24px; 72 | font: { 73 | weight: 800; 74 | size: 18px; 75 | } 76 | text-transform: uppercase; 77 | line-height: 1.66; 78 | code { 79 | text-transform: none; 80 | } 81 | } 82 | 83 | h2 { 84 | margin: { 85 | top: 30px; 86 | bottom: 30px; 87 | } 88 | padding-top: 30px; 89 | border: { 90 | top-style: solid; 91 | color: $gray; 92 | } 93 | &:first-of-type { 94 | border-top-width: 5px; 95 | } 96 | &:not(:first-of-type) { 97 | border-top-width: 1px; 98 | } 99 | } 100 | 101 | h3 { 102 | margin-bottom: 24px; 103 | font: { 104 | weight: 500; 105 | style: italic; 106 | size: 18px; 107 | } 108 | line-height: 1.66; 109 | } 110 | 111 | hr { 112 | margin: { 113 | top: 30px; 114 | bottom: 30px; 115 | } 116 | border: { 117 | top: 1px solid lighten($gray, 13%); 118 | right: none; 119 | bottom: none; 120 | left: none; 121 | } 122 | } 123 | 124 | pre { 125 | padding: 30px; 126 | overflow-x: scroll; 127 | border-radius: 5px; 128 | color: $white; 129 | code { 130 | overflow-x: scroll; 131 | line-height: 1.33; 132 | word-break: normal; 133 | } 134 | } 135 | 136 | code { 137 | font: { 138 | weight: bold; 139 | family: "courier", monospace; 140 | } 141 | } 142 | 143 | ul, ol { 144 | margin-top: 18px; 145 | li { 146 | padding-left: 23px; 147 | text-indent: -23px; 148 | &:not(:first-child) { 149 | margin-top: 12px; 150 | } 151 | } 152 | } 153 | 154 | ul { 155 | li { 156 | &:before { 157 | @extend %bullet; 158 | } 159 | p { 160 | display: inline; 161 | } 162 | } 163 | } 164 | 165 | ol li { 166 | counter-increment: counter; 167 | &:before { 168 | margin-right: 5px; 169 | font-weight: 800; 170 | content: counter(counter, decimal) '. '; 171 | } 172 | } 173 | 174 | li { 175 | word-wrap: break-word; 176 | } 177 | 178 | img { 179 | margin-right: 12px; 180 | height: 32px; 181 | width: 32px; 182 | border: { 183 | radius: 16px; 184 | radius: 50%; 185 | } 186 | } 187 | 188 | table { 189 | width: 100%; 190 | border-collapse: collapse; 191 | } 192 | 193 | thead, tbody { 194 | vertical-align: top; 195 | } 196 | 197 | thead tr { 198 | border-bottom: 5px solid $gray; 199 | } 200 | 201 | th, td { 202 | padding-right: 16px; 203 | } 204 | 205 | th { 206 | padding-bottom: 16px; 207 | text: { 208 | align: left; 209 | transform: uppercase; 210 | } 211 | } 212 | 213 | tbody tr { 214 | border-bottom: 1px solid lighten($gray, 13%); 215 | } 216 | 217 | td { 218 | padding: { 219 | top: 16px; 220 | bottom: 28px; 221 | } 222 | code { 223 | font: { 224 | weight: normal; 225 | size: 13px; 226 | } 227 | } 228 | } 229 | 230 | blockquote { 231 | padding-left: 20px; 232 | border-left: 10px solid lighten($gray, 13%); 233 | p { 234 | font-style: italic; 235 | } 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /resources.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Resources 4 | url: /resources 5 | previous: /run-your-own-gem-server 6 | next: /contributing 7 | --- 8 | 9 | Great blog posts, tutorials, and other sites to help you out. 10 | 11 | A collection of helpful material about RubyGems. Feel free to 12 | [fork](https://github.com/rubygems/guides) and add your own! 13 | 14 | Tutorials 15 | --------- 16 | 17 | * [Making Ruby Gems](http://timelessrepo.com/making-ruby-gems) 18 | * [Gemcutter & Jeweler](http://railscasts.com/episodes/183-gemcutter-jeweler) 19 | * [MicroGems: five minute RubyGems](http://jeffkreeftmeijer.com/2011/microgems-five-minute-rubygems/) - Gems so small that you can store them in a gist. 20 | * [Let's Write a Gem: Part 1](http://rakeroutes.com/blog/lets-write-a-gem-part-one/) and [Part 2](http://rakeroutes.com/blog/lets-write-a-gem-part-two/) 21 | * [Polishing Rubies](http://intridea.com/blog/tag/polishing%20rubies) 22 | * [A Practical Guide to Using Signed Ruby Gems - Part 1: Bundler](http://blog.meldium.com/home/2013/3/3/signed-rubygems-part) 23 | * [Basic RubyGem Development](http://tech.pro/tutorial/1226/basic-rubygem-development) and [Intermediate RubyGem Development](http://tech.pro/tutorial/1277/intermediate-rubygem-development) 24 | * [How to make a Rubygem](http://www.alexedwards.net/blog/how-to-make-a-rubygem) and [How to make a Rubygem: Part Two](http://www.alexedwards.net/blog/how-to-make-a-rubygem-part-two) 25 | * [Crafting Gems](http://railsconftutorials.com/2013/sessions/crafting_gems.html) - A tutorial from RailsConf 2013. 26 | * [How to cryptographically sign your RubyGem](http://www.benjaminfleischer.com/2013/11/08/how-to-sign-your-rubygem-cert/) - Step-by-step guide 27 | 28 | Presentations 29 | ------------- 30 | 31 | * [History of RDoc and RubyGems](http://blog.segment7.net/2011/01/17/history-of-rdoc-and-rubygems) 32 | * [Building a Gem](http://www.slideshare.net/sarah.allen/building-a-ruby-gem) 33 | * [Gemology](http://www.slideshare.net/copiousfreetime/gemology) 34 | 35 | Philosophy 36 | ---------- 37 | 38 | * [Semantic Versioning](http://semver.org/) 39 | * [Ruby Packaging Standard](http://chneukirchen.github.com/rps/) 40 | * [Why `require 'rubygems'` Is Wrong](http://tomayko.com/writings/require-rubygems-antipattern) 41 | * [How to Name Gems](http://blog.segment7.net/2010/11/15/how-to-name-gems) 42 | * [Make the world a better place; put a license in your gemspec](http://www.benjaminfleischer.com/2013/07/12/make-the-world-a-better-place-put-a-license-in-your-gemspec/) 43 | 44 | Patterns 45 | -------- 46 | 47 | * [Gem Packaging: Best Practices](http://weblog.rubyonrails.org/2009/9/1/gem-packaging-best-practices) 48 | * [Rubygems Good Practice](http://yehudakatz.com/2009/07/24/rubygems-good-practice/) 49 | * [Gem Development Best Practices](http://blog.carbonfive.com/2011/01/22/gem-development-best-practices/) 50 | 51 | Creating 52 | -------- 53 | 54 | Tools to help build gems. 55 | 56 | * [gemerator](https://github.com/rkh/gemerator) - Minimalist tool for generating skeleton gems. 57 | * [hoe](https://github.com/seattlerb/hoe) - Rake/RubyGems helper. 58 | * [Jeweler](https://github.com/technicalpickles/jeweler) - Opinionated tool for managing RubyGems projects. 59 | * [micro-cutter](https://github.com/tjh/micro-cutter) - Tool to build the base files for a MicroGem. 60 | * [newgem](https://github.com/drnic/newgem) - New gem generator. 61 | * [RStack](https://github.com/jrun/rstack) - Generator intended for use on private gems. 62 | * [rubygems-tasks](https://github.com/postmodern/rubygems-tasks) - Rake tasks for building, installing, and releasing Ruby Gems. 63 | * [ore](https://github.com/ruby-ore/ore) - Project generator with a variety of templates. 64 | * [Omnibus](https://github.com/opscode/omnibus-ruby) - Generate full-stack installers for ruby code (see this [Omnibus tutorial](http://blog.scoutapp.com/articles/2013/06/21/omnibus-tutorial-package-a-standalone-ruby-gem) for instructions on using it to package a standalone RubyGem.) 65 | 66 | Monitoring 67 | ---------- 68 | 69 | Tools to watch gems for changes. 70 | 71 | * [Gemnasium](https://gemnasium.com/) - Parses your GitHub projects to learn what to notify you about. Free for public repos only. 72 | * [Gemnasium gem](https://github.com/gemnasium/gemnasium-gem) - Allows you to use Gemnasium without granting it access to private repos. 73 | * [gemwhisperer](https://github.com/rubygems/gemwhisperer) 74 | 75 | Hosting and Serving 76 | ------------------- 77 | 78 | * [Geminabox](https://github.com/cwninja/geminabox)- Host your own gems, with a rubygems-compatible API. 79 | * [Gem Mirror](https://github.com/YorickPeterse/gem-mirror) - Run an internal mirror of external gem sources. 80 | * [Gemfury](http://www.gemfury.com/) - Private cloud-based RubyGems servers. Priced by number of collaborators. 81 | 82 | Utilities 83 | --------- 84 | 85 | * [gemnasium-parser](https://github.com/laserlemon/gemnasium-parser) - Determine dependencies without evaluating the ruby in gemfiles or gemspecs 86 | * [Gemrat](https://github.com/DruRly/gemrat) - Add the latest version of a gem to your Gemfile from the command line. 87 | -------------------------------------------------------------------------------- /stylesheets/modules/_header.scss: -------------------------------------------------------------------------------- 1 | .l-wrap--header { 2 | @media (min-width: 1020px) { 3 | position: relative; 4 | max-width: 1100px; 5 | } 6 | @media (min-width: 1020px) and (max-width: 1199px) { 7 | margin: { 8 | right: 5%; 9 | left: 5%; 10 | } 11 | } 12 | @media (min-width: 1200px) { 13 | margin: { 14 | right: auto; 15 | left: auto; 16 | } 17 | } 18 | } 19 | 20 | .header { 21 | -webkit-transform: translateZ(0); // Weird fix to make transition smoother in Safari 22 | @media (max-width: 1019px) { 23 | height: 48px; 24 | } 25 | @media (min-width: 1020px) { 26 | height: 68px; 27 | } 28 | } 29 | 30 | .header--interior { 31 | border-bottom-style: solid; 32 | @media (max-width: 1019px) { 33 | border-bottom: { 34 | width: 1px; 35 | color: darken($red, 10%); 36 | } 37 | } 38 | @media (min-width: 1020px) { 39 | border-bottom: { 40 | width: 7px; 41 | color: $black; 42 | } 43 | box-shadow: inset 0 -2px 0 0 rgba($white, .3); 44 | } 45 | } 46 | 47 | .header__logo-wrap { 48 | position: relative; 49 | float: left; 50 | z-index: 1; 51 | &:focus { 52 | outline: none; 53 | } 54 | &:focus, &:hover { 55 | .header__logo:before { 56 | @include rotate(360deg); 57 | } 58 | } 59 | @media (max-width: 1019px) { 60 | top: 9px; 61 | left: 5%; 62 | font-size: 26px; 63 | } 64 | @media (min-width: 1020px) { 65 | top: 12px; 66 | font-size: 40px; 67 | } 68 | } 69 | 70 | .header__logo { 71 | position: absolute; 72 | font-family: "icomoon"; 73 | @extend %font-smoothing; 74 | color: $white; 75 | speak: none; 76 | @include rotate(0deg); 77 | &:before { 78 | position: absolute; 79 | @extend %font-smoothing; 80 | @include transition-duration(.75s); 81 | @include transition-property(transform); 82 | } 83 | @media (max-width: 1019px) { 84 | line-height: 32px; 85 | } 86 | @media (min-width: 1020px) { 87 | line-height: 45px; 88 | } 89 | } 90 | 91 | .header__club-sandwich { 92 | &:before { 93 | @extend %font-smoothing; 94 | } 95 | @media (max-width: 1019px) { 96 | &:before { 97 | content: '≡'; 98 | margin-right: 5%; 99 | padding: 14px; 100 | position: relative; 101 | right: -14px; 102 | float: right; 103 | font: { 104 | family: "icomoon"; 105 | size: 20px; 106 | } 107 | speak: none; 108 | color: $white; 109 | @include transition-duration(.25s); 110 | @include transition-property(color); 111 | } 112 | &:hover:before, &:focus:before { 113 | color: rgba($white, .3); 114 | } 115 | } 116 | @media (min-width: 1020px) { 117 | display: none; 118 | } 119 | } 120 | 121 | .header__nav-links-wrap { 122 | position: absolute; 123 | @media (max-width: 1019px) { 124 | top: 0; 125 | right: -270px; 126 | width: 270px; 127 | } 128 | @media (min-width: 1020px) { 129 | width: 100%; 130 | } 131 | } 132 | 133 | .header__nav-links { 134 | @media (min-width: 1020px) { 135 | float: right; 136 | } 137 | } 138 | 139 | .header__nav-link { 140 | @extend %box-sizing; 141 | font-weight: 500; 142 | text-transform: uppercase; 143 | color: $white; 144 | @include transition-duration(.25s); 145 | &:focus { 146 | outline: none; 147 | } 148 | @media (max-width: 1019px) { 149 | padding: 18px 30px; 150 | display: block; 151 | width: 100%; 152 | border-bottom: 1px solid darken($red, 10%); 153 | @include transition-property(background-color, border-top-color); 154 | &:focus, &:hover { 155 | border-top-color: darken($red, 10%); 156 | background-color: darken($red, 10%); 157 | } 158 | &:active, &.is-active { 159 | background-color: $white; 160 | color: $red; 161 | } 162 | } 163 | @media (min-width: 1020px) { 164 | display: inline-block; 165 | padding: { 166 | top: 25px; 167 | bottom: 26px; 168 | } 169 | margin: { 170 | right: 16px; 171 | left: 16px; 172 | } 173 | border-bottom: 5px solid transparent; 174 | box-shadow: inset 0 5px 0 0 transparent; 175 | @include transition-property(box-shadow); 176 | &:last-child { 177 | margin-right: -16px; 178 | } 179 | &:focus, &:hover { 180 | box-shadow: inset 0 5px 0 0 $white; 181 | } 182 | &.is-active { 183 | position: relative; 184 | border-bottom-color: $red; 185 | &:after { 186 | content: ""; 187 | position: absolute; 188 | bottom: -10px; 189 | @include calc(left, "50% - 5px", 50%); 190 | border: { 191 | width: 5px 5px 0; 192 | style: solid; 193 | color: $red transparent; 194 | } 195 | display: block; 196 | } 197 | } 198 | } 199 | span { 200 | display: inline-block; 201 | position: relative; 202 | max-width: 150px; 203 | overflow: hidden; 204 | text-overflow: ellipsis; 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | gem "rdoc" 2 | 3 | require 'rdoc/rdoc' 4 | require 'rdoc/task' 5 | require 'fileutils' 6 | 7 | $:.unshift '.', '../rubygems/lib' 8 | 9 | ENV['RUBYGEMS_DIR'] ||= File.expand_path '../../rubygems', __FILE__ 10 | 11 | task :RUBYGEMS_DIR_exists do 12 | message = <<-NO_RUBYGEMS_DIR 13 | The Rubygems rdocs are required to build the spec guide. 14 | 15 | Install or clone it from GitHub, then: 16 | 17 | RUBYGEMS_DIR=/path/to/rubygems/source rake spec_guide --trace 18 | 19 | The RUBYGEMS_DIR is assumed to exist at: 20 | 21 | #{ENV['RUBYGEMS_DIR']} 22 | NO_RUBYGEMS_DIR 23 | 24 | abort message unless File.exist? ENV['RUBYGEMS_DIR'] 25 | end 26 | 27 | # RUBYGEMS_DIR should be checked first 28 | task rdoc_spec: %w[RUBYGEMS_DIR_exists] 29 | 30 | RDoc::Task.new(:rdoc_spec) do |rd| 31 | spec_file = File.join(ENV["RUBYGEMS_DIR"].to_s, "lib", "rubygems", "specification.rb") 32 | rd.rdoc_files.include(spec_file) 33 | rd.template = "jekdoc" 34 | rd.options << '--quiet' 35 | end 36 | 37 | desc "move spec guide into the right place" 38 | task :move_spec => %w[specification-reference.md] 39 | 40 | file 'html/Gem/Specification.html' => %w[rdoc_spec] 41 | 42 | file 'specification-reference.md' => %w[html/Gem/Specification.html] do 43 | cp 'html/Gem/Specification.html', 'specification-reference.md' 44 | end 45 | 46 | desc "clean up after rdoc" 47 | task :clean do 48 | FileUtils.rm_rf "html" 49 | end 50 | 51 | desc "generate specification guide" 52 | task :spec_guide => [:rdoc_spec, :move_spec, :clean] 53 | 54 | desc "generate command guide" 55 | task :command_guide => %w[command-reference.md] 56 | 57 | command_reference_files = Rake::FileList.new(*%W[ 58 | Rakefile 59 | command-reference.erb 60 | #{ENV['RUBYGEMS_DIR']}/lib/rubygems.rb 61 | #{ENV['RUBYGEMS_DIR']}/lib/rubygems/command_manager.rb 62 | #{ENV['RUBYGEMS_DIR']}/lib/rubygems/commands/*.rb 63 | ]) 64 | 65 | file 'command-reference.md' => 66 | %w[RUBYGEMS_DIR_exists] + command_reference_files do 67 | require 'rubygems/command_manager' 68 | require 'rdoc/erbio' 69 | 70 | rubygems_version = Gem.rubygems_version.version 71 | names = Gem::CommandManager.instance.command_names 72 | commands = {} 73 | names.each do |name| 74 | command = Gem::CommandManager.instance[name] 75 | command.options[:help] = '' 76 | commands[name] = command 77 | end 78 | 79 | def htmlify(string) 80 | lines = string.split("\n") 81 | html_string = '' 82 | lines.each do |line| 83 | if line 84 | if line =~ /^ / 85 | # This will end up in a block
86 | html_string += line
87 | else
88 | html_string += line.gsub("<", "<").gsub(">", ">")
89 | end
90 | html_string += "\n"
91 | end
92 | end
93 | html_string[0..-2]
94 | end
95 |
96 | def argument_list_item(string)
97 | if string =~ /^(\S+)(.*)/
98 | string = "*#{$1}* - #{$2}"
99 | end
100 | htmlify("* #{string}")
101 | end
102 |
103 | def options_list(command)
104 | ui = Gem::SilentUI.new
105 | Gem::DefaultUserInteraction.use_ui ui do
106 | # Invoke the Ruby options parser by asking for help. Otherwise the
107 | # options list in the parser will never be initialized.
108 | command.show_help
109 | end
110 |
111 | parser = command.send(:parser)
112 | options = ''
113 | helplines = parser.summarize
114 | helplines.each do |helpline|
115 | break if (helpline =~ /Arguments/) || (helpline =~ /Summary/)
116 | unless helpline.gsub(/\n/, '').strip == ''
117 | # Use zero-width space to prevent "helpful" change of -- to –
118 | helpline = helpline.gsub('--', '--').gsub('[', '\\[').gsub(']', '\\]')
119 |
120 | if helpline =~ /^\s{10,}(.*)/
121 | options = options[0..-2] + " #{$1}\n"
122 | else
123 | if helpline =~ /^(.*)\s{3,}(.*)/
124 | helpline = "#{$1} - #{$2}"
125 | end
126 | if helpline =~ /options/i
127 | options += "\n### #{helpline}\n"
128 | else
129 | options += "* #{helpline}\n"
130 | end
131 | end
132 | end
133 | end
134 | options
135 | end
136 |
137 | filename = "command-reference.erb"
138 |
139 | erbio = RDoc::ERBIO.new File.read(filename), nil, nil
140 | erbio.filename = filename
141 |
142 | open 'command-reference.md', 'w' do |io|
143 | erbio.result binding
144 | end
145 | end
146 |
147 | desc "serve documentation on http://localhost:4000"
148 | task :server do
149 | pids = [
150 | spawn('jekyll', 'serve', '4000'),
151 | spawn('scss', '--watch', 'stylesheets:stylesheets'),
152 | ]
153 |
154 | trap "INT" do
155 | Process.kill "INT", *pids
156 | exit 1
157 | end
158 |
159 | trap "TERM" do
160 | Process.kill "TERM", *pids
161 | exit 1
162 | end
163 |
164 | pids.each do |pid|
165 | Process.waitpid pid
166 | end
167 | end
168 |
169 | desc 'build documentation and display it on http://localhost:4000'
170 | task default: %w[spec_guide command_guide server]
171 |
172 |
--------------------------------------------------------------------------------
/stylesheets/screen.scss:
--------------------------------------------------------------------------------
1 | @import 'flutie';
2 |
3 | body {
4 | font-family: helvetica neue, helvetica, sans-serif;
5 | line-height: 1;
6 | }
7 | body.home {
8 | background: url("/images/background.jpg") repeat;
9 | }
10 |
11 | .left {
12 | float: left;
13 | }
14 | .right {
15 | float: right;
16 | }
17 |
18 | #head-wrapper {
19 | background: #240101 url("/images/background.jpg") repeat;
20 | width: 100%;
21 |
22 | #small-top {
23 | margin: 0 auto;
24 | padding: 20px 0;
25 | max-width: 480px;
26 |
27 | header {
28 | margin: 0 auto;
29 | height: 75px;
30 | max-width: 450px;
31 |
32 | a {
33 | text-decoration: none;
34 | }
35 |
36 | h1 {
37 | background: url("/images/logo-small.png") 5px 0 no-repeat;
38 | float: left;
39 | height: 70px;
40 | padding-top: 13px;
41 | text-indent: 90px;
42 | color: white;
43 | font: 300 42px/42px "proxima-nova-1", "proxima-nova-2", "museo-sans-1", "museo-sans-2", helvetica neue, sans-serif;
44 | letter-spacing: 1px;
45 | text-shadow: 0 0 1px #333;
46 | }
47 | }
48 | }
49 |
50 | #homepage-top {
51 | margin: 0 auto;
52 | padding: 30px 0;
53 | width: 978px;
54 |
55 | header {
56 | height: 150px;
57 |
58 | h1 {
59 | background: url("/images/logo.png") 5px 0 no-repeat;
60 | float: left;
61 | height: 150px;
62 | text-indent: -9999px;
63 | width: 168px;
64 | }
65 |
66 | #the-sell {
67 | float: left;
68 | margin: 25px 0 0 0;
69 | width: 726px;
70 |
71 | h2 {
72 | color: white;
73 | font: 300 42px/42px helvetica neue, sans-serif;
74 | letter-spacing: 1px;
75 | text-shadow: 0 0 1px #333;
76 | }
77 |
78 | p.tagline {
79 | color: #CCC;
80 | font: 300 18px/22px helvetica neue, sans-serif;
81 | margin: 6px 0 0 0;
82 | text-shadow: 0 0 1px #333;
83 |
84 | a, a:visited, a:link {
85 | color: #ccc;
86 | }
87 | }
88 | }
89 | }
90 |
91 | #chapters {
92 | margin: 0 0 0 168px;
93 |
94 | a, a:visited, a:link {
95 | color: #fff;
96 | text-decoration: none;
97 | }
98 |
99 | a:hover {
100 | color: #AD141E;
101 | }
102 |
103 | h2 {
104 | color: white;
105 | font: 700 30px/32px "proxima-nova-1", "proxima-nova-2", "museo-sans-1", "museo-sans-2", helvetica neue, sans-serif;
106 | text-shadow: 0 1px 1px #222;
107 | margin-top: 20px;
108 | }
109 |
110 | p {
111 | color: #AAA;
112 | font: 300 16px/18px "proxima-nova-1", "proxima-nova-2", "museo-sans-1", "museo-sans-2", helvetica neue, sans-serif;
113 | margin: 4px 122px 0 0;
114 |
115 | a, a:visited, a:link {
116 | color: #AAA;
117 | }
118 |
119 | a:hover {
120 | color: #AD141E;
121 | }
122 |
123 | }
124 |
125 | p.introduction {
126 | margin-bottom: 1.5em;
127 | line-height: 1.3em;
128 | width: 70%;
129 | color: #CCC;
130 | }
131 | }
132 | }
133 | }
134 |
135 | #container {
136 | margin: 0 auto;
137 | max-width: 480px;
138 | padding: 0 7px;
139 |
140 | .nav {
141 | margin: 25px 0 0 0;
142 | height: 24px;
143 | text-transform: uppercase;
144 | font-size: 16px;
145 | width: 100%;
146 |
147 | a {
148 | color: #AD141E;
149 | text-decoration: none;
150 | }
151 | a:hover {
152 | text-decoration: underline;
153 | }
154 | }
155 |
156 | #content {
157 | font: 400 16px/24px helvetica neue, sans-serif;
158 |
159 | a {
160 | color: #AD141E;
161 | }
162 |
163 | h1 {
164 | font: 700 30px/50px helvetica neue, sans-serif;
165 | padding-top: 10px;
166 | a {
167 | color: #000;
168 | text-decoration: none;
169 | }
170 | }
171 |
172 | h2 {
173 | font-size: 18px;
174 | font-weight: bold;
175 | margin: 25px 0;
176 | clear: both;
177 | border-top: 1px solid #ddd;
178 | padding-top: 10px;
179 | }
180 |
181 | h3 {
182 | font-size: 14px;
183 | }
184 |
185 | p {
186 | margin: 1em 0;
187 | }
188 |
189 | pre {
190 | overflow: auto;
191 | background: #333;
192 | color: #fff;
193 | padding: 10px;
194 | font-family: Monaco, Consolas, "Courier New", Courier, Sans-serif;
195 |
196 | code {
197 | background: #333;
198 | }
199 | }
200 |
201 | code {
202 | background: #eee;
203 | padding: 2px;
204 | }
205 |
206 | tt {
207 | display: inline;
208 | }
209 |
210 | ul, ol {
211 | padding-top: 10px;
212 | margin-left: 30px;
213 | list-style: square;
214 |
215 | li {
216 | padding-bottom: 0px;
217 | }
218 | }
219 |
220 | ol {
221 | list-style: decimal;
222 | }
223 | }
224 |
225 | footer {
226 | margin: 50px 0;
227 | text-align: center;
228 | p {
229 | color: #666;
230 | font: 400 14px "proxima-nova-1", "proxima-nova-2", "museo-sans-1", "museo-sans-2", helvetica neue, sans-serif;
231 | a, a:visited, a:link {
232 | color: #666;
233 | }
234 | }
235 | }
236 | }
237 |
--------------------------------------------------------------------------------
/faqs.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Frequently Asked Questions
4 | url: /faqs
5 | previous: /contributing
6 | next: /plugins
7 | ---
8 |
9 | More of the "why" and "wtf" than "how".
10 |
11 | The RubyGems development team has gotten a lot of support requests over the
12 | years, and this is a list of the questions users both new and old that
13 | frequently pop up.
14 |
15 | * [I installed gems with `--user-install` and their commands are not available](#user-install)
16 | * [How can I trust Gem code that's automatically downloaded?](#security)
17 | * [Why does `require 'some-gem'` fail?](#require-fail)
18 | * [Why does require return false when loading a file from a gem?](#require-false)
19 |
20 | We also answer questions on the [RubyGems Support](http://help.rubygems.org/) site and on IRC
21 | in #rubygems. Some of the information you can find on the support site includes:
22 |
23 | * [Installing gems with no network](http://help.rubygems.org/kb/rubygems/installing-gems-with-no-network)
24 | * [Why do I get HTTP Response 302 or 301 when installing a gem?](http://help.rubygems.org/kb/rubygems/why-do-i-get-http-response-302-or-301-when-installing-a-gem)
25 | * [RubyGems Upgrade Issues](http://help.rubygems.org/kb/rubygems/rubygems-upgrade-issues)
26 |
27 |
28 |
29 | I installed gems with `--user-install` and their commands are not available
30 | ---------------------------------------------------------------------------
31 |
32 | When you use the `--user-install` option, RubyGems will install the gems to a
33 | directory inside your home directory, something like `~/.gem/ruby/1.9.1`. The
34 | commands provided by the gems you installed will end up in
35 | `~/.gem/ruby/1.9.1/bin`. For the programs installed there to be available for
36 | you, you need to add `~/.gem/ruby/1.9.1/bin` to your `PATH` environment
37 | variable.
38 |
39 | For example, if you use bash you can add that directory to your `PATH` by
40 | adding code like this to your `~/.bashrc` file:
41 |
42 | if which ruby >/dev/null && which gem >/dev/null; then
43 | PATH="$(ruby -rubygems -e 'puts Gem.user_dir')/bin:$PATH"
44 | fi
45 |
46 | After adding this code to your `~/.bashrc`, you need to restart your shell for
47 | the changes to take effect. You can do this by opening a new terminal window or
48 | by running `exec $SHELL` in the window you already have open.
49 |
50 |
51 |
52 | How can I trust Gem code that's automatically downloaded?
53 | ---------------------------------------------------------
54 |
55 | The same way you can trust any other code you install from the net: ultimately,
56 | you can't. You are responsible for knowing the source of the gems that you are
57 | using. In a setting where security is critical, you should only use known-good
58 | gems, and possibly perform your own security audit on the gem code.
59 |
60 | The Ruby community is discussing ways to make gem code more secure in the future,
61 | using some public-key infrastructure. To see the progress of this discussion, visit the
62 | [rubygems-trust](https://github.com/rubygems-trust) organization on GitHub.
63 |
64 |
65 |
66 | Why does `require 'some-gem'` fail?
67 | -----------------------------------
68 |
69 | Not every library has a strict mapping between the name of the gem and the name of
70 | the file you need to require. First you should check to see if the files match correctly:
71 |
72 | $ gem list RedCloth
73 |
74 | *** LOCAL GEMS ***
75 |
76 | RedCloth (4.1.1)
77 | $ ruby -rubygems -e 'require "RedCloth"'
78 | /Library/Ruby/Site/1.8/rubygems/custom_require.rb:31:in `gem_original_require': no such file to load -- RedCloth (LoadError)
79 | from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:31:in `require'
80 | from -e:1
81 | $ gem contents --no-prefix RedCloth | grep lib
82 | lib/case_sensitive_require/RedCloth.rb
83 | lib/redcloth/erb_extension.rb
84 | lib/redcloth/formatters/base.rb
85 | lib/redcloth/formatters/html.rb
86 | lib/redcloth/formatters/latex.rb
87 | lib/redcloth/formatters/latex_entities.yml
88 | lib/redcloth/textile_doc.rb
89 | lib/redcloth/version.rb
90 | lib/redcloth.rb
91 | $ ruby -rubygems -e 'require "redcloth"'
92 | $ # success!
93 |
94 | If you’re requiring the correct file, maybe `gem` is using a different ruby than `ruby`:
95 |
96 | $ which ruby
97 | /usr/local/bin/ruby
98 | $ gem env | grep 'RUBY EXECUTABLE'
99 | - RUBY EXECUTABLE: /usr/local/bin/ruby1.9
100 |
101 | In this instance we’ve got two ruby installations so that `gem` uses a different version than `ruby`. You can probably fix this by adjusting a symlink:
102 |
103 | $ ls -l /usr/local/bin/ruby*
104 | lrwxr-xr-x 1 root wheel 76 Jan 20 2010 /usr/local/bin/ruby@ -> /usr/local/bin/ruby1.8
105 | -rwxr-xr-x 1 root wheel 1213160 Jul 15 16:36 /usr/local/bin/ruby1.8*
106 | -rwxr-xr-x 1 root wheel 2698624 Jul 6 19:30 /usr/local/bin/ruby1.9*
107 | $ ls -l /usr/local/bin/gem*
108 | lrwxr-xr-x 1 root wheel 76 Jan 20 2010 /usr/local/bin/gem@ -> /usr/local/bin/gem1.9
109 | -rwxr-xr-x 1 root wheel 550 Jul 15 16:36 /usr/local/bin/gem1.8*
110 | -rwxr-xr-x 1 root wheel 550 Jul 6 19:30 /usr/local/bin/gem1.9*
111 |
112 | You may also need to give `irb` the same treatment.
113 |
114 |
115 |
116 | Why does require return false when loading a file from a gem?
117 | -------------------------------------------------------------
118 |
119 | Require returns false when loading a file from a gem. Usually require will return
120 | true when it has loaded correctly. What’s wrong?
121 |
122 | Nothing's wrong. Well, something. But nothing you need to worry about.
123 |
124 | A false return from the require method does not indicate an error. It just
125 | means that the file has already been loaded.
126 |
127 | RubyGems has a feature that allows a file to be automatically loaded
128 | when a gem is activated (i.e. selected). When you require a file that is
129 | in an inactive gem, the RubyGems software will activate that gem for you.
130 | During that activation, any autoloaded files will be loaded for you.
131 |
132 | So, by the time your require statement actually does the work of loading
133 | the file, it has already been autoloaded via the gem activation, and
134 | therefore the statement returns false.
135 |
136 |
--------------------------------------------------------------------------------
/security.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Security
4 | url: /security
5 | previous: /publishing
6 | next: /patterns
7 | ---
8 |
9 | How to build and install cryptographically signed gems-- and other security concerns.
10 |
11 | Security practices are being actively discussed. Check back often.
12 |
13 | * [General](#general)
14 | * [Using Gems](#using-gems)
15 | * [Building Gems](#building-gems)
16 | * [Reporting Security Vulnerabilities](#reporting-security-vulnerabilities)
17 |
18 | General
19 | -------
20 |
21 | Installing a gem allows that gem's code to run in the context of your
22 | application. Clearly this has security implications: installing a malicious gem
23 | on a server could ultimately result in that server being completely penetrated
24 | by the gem's author. Because of this, the security of gem code is a topic of
25 | active discussion within the Ruby community.
26 |
27 | RubyGems has had the ability to [cryptographically sign
28 | gems](http://docs.seattlerb.org/rubygems/Gem/Security.html) since version
29 | 0.8.11. This signing works by using the `gem cert` command to create a key
30 | pair, and then packaging signing data inside the gem itself. The `gem install`
31 | command optionally lets you set a security policy, and you can verify the
32 | signing key for a gem before you install it.
33 |
34 | However, this method of securing gems is not widely used. It requires a number
35 | of [manual steps on the part of the developer](#building-gems), and there is no
36 | well-established chain of trust for gem signing keys. Discussion of new
37 | signing models such as X509 and OpenPGP is going on in the [rubygems-trust
38 | wiki](https://github.com/rubygems-trust/rubygems.org/wiki/_pages), the
39 | [RubyGems-Developers
40 | list](https://groups.google.com/d/msg/rubygems-developers/lnnGTlfsuYo/TLDcJ2RPSDoJ)
41 | and in [IRC](irc://chat.freenode.net/#rubygems-trust). The goal is to improve
42 | (or replace) the signing system so that it is easy for authors and transparent
43 | for users.
44 |
45 | Using Gems
46 | -------
47 |
48 | Install with a trust policy.
49 |
50 | * `gem install gemname -P HighSecurity`: All dependent gems must be signed
51 | and verified.
52 |
53 | * `gem install gemname -P MediumSecurity`: All signed dependent gems must be
54 | verified.
55 |
56 | * `bundle --trust-policy MediumSecurity`: Same as above, except Bundler only
57 | recognizes the long `--trust-policy` flag, not the short `-P`.
58 |
59 | * *Caveat:* Gem certificates are trusted globally, such that adding a
60 | cert.pem for one gem automatically trusts all gems signed by that cert.
61 |
62 | Verify the checksum, if available
63 |
64 | gem fetch gemname -v version
65 | ruby -rdigest/sha2 -e "puts Digest::SHA512.new.hexdigest(File.read('gemname-version.gem'))
66 |
67 | Know the risks of being pwned, as described by [Benjamin Smith's Hacking with Gems talk](http://lanyrd.com/2013/rulu/scgxzr/)
68 |
69 | Building Gems
70 | -------
71 |
72 | ### Sign with: `gem cert`
73 |
74 | 1) Create self-signed gem cert
75 |
76 | cd ~/.ssh
77 | gem cert --build your@email.com
78 | chmod 600 gem-p*
79 |
80 | - use the email address you specify in your gemspecs
81 |
82 | 2) Configure gemspec with cert
83 |
84 | Add cert public key to your repository
85 |
86 | cd /path/to/your/gem
87 | mkdir certs
88 | cp ~/.ssh/gem-public_cert.pem certs/yourhandle.pem
89 | git add certs/yourhandle.pem
90 |
91 | Add cert paths to your gemspec
92 |
93 | s.cert_chain = ['certs/yourhandle.pem']
94 | s.signing_key = File.expand_path("~/.ssh/gem-private_key.pem") if $0 =~ /gem\z/
95 |
96 | 3) Add your own cert to your approved list, just like anyone else
97 |
98 | gem cert --add certs/yourhandle.pem
99 |
100 | 4) Build gem and test that you can install it
101 |
102 | gem build gemname.gemspec
103 | gem install gemname-version.gem -P HighSecurity
104 | # or -P MediumSecurity if your gem depends on unsigned gems
105 |
106 | 5) Example text for installation documentation
107 |
108 | > MetricFu is cryptographically signed. To be sure the gem you install hasn't been tampered with:
109 | >
110 | > Add my public key (if you haven't already) as a trusted certificate
111 | >
112 | > `gem cert --add <(curl -Ls https://raw.github.com/metricfu/metric_fu/master/certs/bf4.pem)`
113 | >
114 | > `gem install metric_fu -P MediumSecurity`
115 | >
116 | > The MediumSecurity trust profile will verify signed gems, but allow the installation of unsigned dependencies.
117 | >
118 | > This is necessary because not all of MetricFu's dependencies are signed, so we cannot use HighSecurity.
119 |
120 | -------
121 |
122 | ### Include checksum of released gems in your repository
123 |
124 | require 'digest/sha2'
125 | built_gem_path = 'pkg/gemname-version.gem'
126 | checksum = Digest::SHA512.new.hexdigest(File.read(built_gem_path))
127 | checksum_path = 'checksum/gemname-version.gem.sha512'
128 | File.open(checksum_path, 'w' ) {|f| f.write(checksum) }
129 | # add and commit 'checksum_path'
130 |
131 | -------
132 |
133 | ### OpenPGP signing is [not recommended due to lack of support](http://www.rubygems-openpgp-ca.org/blog/nobody-cares-about-signed-gems.html).
134 |
135 | For details, see discussion [with Yorick
136 | Peterse](https://github.com/rubygems/guides/pull/70#issuecomment-29007487).
137 |
138 | Reporting Security vulnerabilities
139 | -------
140 |
141 |
142 | ### Reporting a security vulnerability with someone else's gem
143 |
144 | If you spot a security vulnerability in someone else's gem, then you
145 | first step should be to check whether this is a known vulnerability.
146 |
147 | If this looks like a newly discovered vulnerability then you should
148 | contact the author(s) privately (i.e. not via a pull request or issue on public
149 | project) explaining the issue, how it can be exploited and ideally offering an
150 | indication of how it might be fixed.
151 |
152 | ### Reporting a security vulnerability with your own gem
153 |
154 | Firstly request a [CVE
155 | identifier](https://en.wikipedia.org/wiki/Common_Vulnerabilities_and_Exposures)
156 | by mailing cve-assign@mitre.org. This identifier will make it easy to
157 | uniquely identify the vulnerability when talking about it.
158 |
159 | Secondly work out what people who depend on your gem should do to
160 | resolve the vulnerability. This may involve releasing a patched version of you gem
161 | that you can recommend they upgrade to.
162 |
163 | Finally you need to tell people about the vulnerability. Currently there
164 | is no single place to broadcast this information but a good place to
165 | start might be to:
166 |
167 | - Send an email to the Ruby Talk mailing list (ruby-talk@ruby-lang.org)
168 | with the subject prefix \[ANN]\[Security] outlining the vulnerabilty,
169 | which versions of your gem it affects and what actions those depending
170 | on the gem should take.
171 |
172 | - Add it to an open source vulnerability database like
173 | [OSVDB](http://osvdb.org/). You can do this by emailing moderators@osvdb.org
174 | and/or messaging @osvdb on GitHub or Twitter.
175 |
176 | Credits
177 | -------
178 |
179 | Several sources were used for content for this guide:
180 |
181 | * [How to cryptographically sign your RubyGem](http://www.benjaminfleischer.com/2013/11/08/how-to-sign-your-rubygem-cert/) - Step-by-step guide
182 | * [Signing rubygems - Pasteable instructions](http://developer.zendesk.com/blog/2013/02/03/signing-gems/)
183 | * [Twitter gem gemspec](https://github.com/sferik/twitter/blob/master/twitter.gemspec)
184 | * [RubyGems Trust Model Overview](https://github.com/rubygems-trust/rubygems.org/wiki/Overview), [doc](http://goo.gl/ybFIO)
185 | * [Let’s figure out a way to start signing RubyGems](http://tonyarcieri.com/lets-figure-out-a-way-to-start-signing-rubygems)
186 | * [A Practical Guide to Using Signed Ruby Gems - Part 3: Signing your Own](http://blog.meldium.com/home/2013/3/6/signing-gems-how-to)
187 | * Also see the [Resources](/resources) page.
188 |
--------------------------------------------------------------------------------
/plugins.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Plugins
4 | url: /plugins
5 | previous: /faqs
6 | next: /credits
7 | ---
8 |
9 | Extensions that use the RubyGems plugin API.
10 |
11 | As of RubyGems 1.3.2, RubyGems will load plugins installed in gems or $LOAD\_PATH. Plugins must be named 'rubygems\_plugin' (.rb, .so, etc) and placed at the root of your gem's #require\_path. Plugins are discovered via Gem::find\_files then loaded. Take care when implementing a plugin as your plugin file may be loaded multiple times if multiple versions of your gem are installed.
12 |
13 | The following list of RubyGems plugins is probably not exhaustive. If you know of plugins that we missed, feel free to update this page.
14 |
15 | * [executable-hooks](#executablehooks)
16 | * [gem-browse](#gembrowse)
17 | * [gem-ctags](#gemctags)
18 | * [gem-empty](#gemempty)
19 | * [gem_info](#geminfo)
20 | * [gem-init](#geminit)
21 | * [gem-compare](#gemcompare)
22 | * [gem-man](#gemman)
23 | * [gem-nice-install](#gemniceinstall)
24 | * [gem-orphan](#gemorphan)
25 | * [gem-patch](#gempatch)
26 | * [gem-toolbox](#gemtoolbox)
27 | * [gem-wrappers](#gemwrappers)
28 | * [graph](#graph)
29 | * [maven-gem](#mavengem)
30 | * [open-gem](#opengem)
31 | * [PushSafety](#pushsafety)
32 | * [rbenv-rehash](#rbenvrehash)
33 | * [rubygems-desc](#rubygemsdesc)
34 | * [rubygems-openpgp](#rubygemsopenpgp)
35 | * [rubygems-sandbox](#rubygemssandbox)
36 | * [rubygems_snapshot](#rubygemssnapshot)
37 | * [rubygems-tasks](#rubygemstasks)
38 |
39 |
40 |
41 | ## executable-hooks
42 |
43 | [https://github.com/mpapis/executable-hooks](https://github.com/mpapis/executable-hooks)
44 |
45 | Extends rubygems to support executables plugins.
46 |
47 | In gem lib dir create rubygems_executable_plugin.rb:
48 |
49 | Gem.execute do |original_file|
50 | warn("Executing: #{original_file}")
51 | end
52 |
53 |
54 |
55 |
56 | ## gem-browse
57 |
58 | [https://github.com/tpope/gem-browse](https://github.com/tpope/gem-browse)
59 |
60 | Adds four commands:
61 |
62 | - `gem edit` opens a gem in your editor
63 | - `gem open` opens a gem by name in your editor
64 | - `gem clone` clones a gem from GitHub
65 | - `gem browse` opens a gem's homepage in your browser
66 |
67 |
68 |
69 | ## gem-empty
70 |
71 | [https://github.com/rvm/gem-empty](https://github.com/rvm/gem-empty)
72 |
73 | Adds command `gem empty` to remove all gems from current `GEM_HOME`.
74 |
75 |
76 |
77 | ## gem-ctags
78 |
79 | [https://github.com/tpope/gem-ctags](https://github.com/tpope/gem-ctags)
80 |
81 | Adds a `gem ctags` command to invoke the Exuberant Ctags indexer on already-installed gems, and then automatically invokes it on gems as they are installed.
82 |
83 |
84 |
85 | ## gem_info
86 |
87 | [https://github.com/oggy/gem_info](https://github.com/oggy/gem_info)
88 |
89 | Adds a `gem info` command with fuzzy matching on name and version. Designed for scripting use.
90 |
91 |
92 |
93 | ## gem-init
94 |
95 | [https://github.com/mwhuss/gem-init](https://github.com/mwhuss/gem-init)
96 |
97 | Adds `gem init` to create a barebones gem.
98 |
99 |
100 |
101 | ## gem-compare
102 |
103 | [https://github.com/strzibny/gem-compare](https://github.com/strzibny/gem-compare)
104 |
105 | Adds `gem compare` command that can help you to track upstream changes in the released
106 | .gem files by comparing gemspec values, gemspec and Gemfile dependencies and files.
107 |
108 |
109 |
110 |
111 | ## gem-man
112 |
113 | [https://github.com/defunkt/gem-man](https://github.com/defunkt/gem-man)
114 |
115 | The `gem man` command lets you view a gem's man page.
116 |
117 |
118 |
119 | ## gem-nice-install
120 |
121 | [https://github.com/voxik/gem-nice-install](https://github.com/voxik/gem-nice-install)
122 |
123 | Tries to install system dependencies needed to install your gems with binary extensions
124 | using standard `gem install` command. This currently works only for Fedora, but
125 | hopefully will be extended.
126 |
127 |
128 |
129 | ## gem-orphan
130 |
131 | [https://github.com/sakuro/gem-orphan](https://github.com/sakuro/gem-orphan)
132 |
133 | Adds a `gem orphan` command that finds and lists gems on which no other gems are depending.
134 |
135 |
136 |
137 | ## gem-patch
138 |
139 | [https://github.com/strzibny/gem-patch](https://github.com/strzibny/gem-patch)
140 |
141 | Adds `gem patch` command, which enables you to apply patches directly on `.gem` files.
142 | Supports both RubyGems 1.8 and RubyGems 2.0.
143 |
144 |
145 |
146 | ## gem-toolbox
147 |
148 | [https://github.com/gudleik/gem-toolbox](https://github.com/gudleik/gem-toolbox)
149 |
150 | Adds six commands:
151 |
152 | - `gem open` - opens a gem in your default editor
153 | - `gem cd` - changes your working directory to the gem's source root
154 | - `gem readme` - locates and displays a gem's readme file
155 | - `gem history` - locates and display's a gem's changelog
156 | - `gem doc` - Browse a gem's documentation in your default browser
157 | - `gem visit` - Open a gem's homepage in your default browser
158 |
159 |
160 |
161 | ## gem-wrappers
162 |
163 | [https://github.com/rvm/gem-wrappers](https://github.com/rvm/gem-wrappers)
164 |
165 | Create gem wrappers for easy use of gems in cron and other system locations.
166 | By default wrappers are installed when a gem is installed.
167 |
168 | Adds this commands:
169 |
170 | - `gem wrappers regenerate` - force rebuilding wrappers for all gem executables
171 | - `gem wrappers` - show current configuration
172 |
173 |
174 |
175 | ## graph
176 |
177 | [https://github.com/seattlerb/graph](https://github.com/seattlerb/graph)
178 |
179 | Adds a `gem graph` command to output a gem dependency graph in graphviz's dot format.
180 |
181 |
182 |
183 | ## maven_gem
184 |
185 | [https://github.com/jruby/maven_gem](https://github.com/jruby/maven_gem)
186 |
187 | Adds `gem maven` to install any Maven-published Java library as though it were a gem.
188 |
189 |
190 |
191 | ## open_gem
192 |
193 | [https://github.com/adamsanderson/open_gem](https://github.com/adamsanderson/open_gem)
194 |
195 | Adds two commands:
196 |
197 | - `gem open` opens a gem in your default editor
198 | - `gem read` opens a gem's rdoc in your default browser
199 |
200 |
201 |
202 | ## PushSafety
203 |
204 | [https://github.com/jdleesmiller/push_safety](https://github.com/jdleesmiller/push_safety)
205 |
206 | Applies a whitelist to `gem push` to prevent accidentally pushing private gems to the public RubyGems repository.
207 |
208 |
209 |
210 | ## rbenv-rehash
211 |
212 | [https://github.com/scoz/rbenv-rehash](https://github.com/scoz/rbenv-rehash)
213 |
214 | Automatically runs `rbenv rehash` after installing or uninstalling gems.
215 |
216 |
217 |
218 | ## rubygems-desc
219 |
220 | [https://github.com/chad/rubygems-desc](https://github.com/chad/rubygems-desc)
221 |
222 | Adds `gem desc` to describe a gem by name.
223 |
224 |
225 |
226 | ## rubygems-openpgp
227 |
228 | [https://github.com/grant-olson/rubygems-openpgp](https://github.com/grant-olson/rubygems-openpgp)
229 |
230 | Adds commands and flags to allow OpenPGP signing of gems.
231 |
232 | - `gem sign foo.gem` to sign a gem.
233 | - `gem verify foo.gem --trust` to verify a gem.
234 | - `gem build foo.gemspec --sign` to sign at build time.
235 | - `gem install foo --verify --trust` to verify on install.
236 |
237 |
238 |
239 | ## rubygems-sandbox
240 |
241 | [https://github.com/seattlerb/rubygems-sandbox](https://github.com/seattlerb/rubygems-sandbox)
242 |
243 | Manages command-line gem tools and dependencies with a `gem sandbox` command. This lets you install things like flay and rdoc outside of the global rubygems repository.
244 |
245 |
246 |
247 | ## rubygems_snapshot
248 |
249 | [https://github.com/rogerleite/rubygems_snapshot](https://github.com/rogerleite/rubygems_snapshot)
250 |
251 | Adds `gem snapshot` to create exports of all your current gems into a single file that you can import later.
252 |
253 |
254 |
255 | ## rubygems-tasks
256 |
257 | [https://github.com/postmodern/rubygems-tasks](https://github.com/postmodern/rubygems-tasks#readme)
258 |
259 | rubygems-tasks provides agnostic and unobtrusive Rake tasks for building, installing and releasing Ruby Gems.
260 |
--------------------------------------------------------------------------------
/rubygems-basics.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: RubyGems Basics
4 | url: /rubygems-basics
5 | previous: /
6 | next: /what-is-a-gem
7 | ---
8 |
9 | Use of common RubyGems commands
10 |
11 | The `gem` command allows you to interact with RubyGems.
12 |
13 | Ruby 1.9 and newer ships with RubyGems built-in but you may need to upgrade for
14 | bug fixes or new features. To upgrade RubyGems or install it for the first
15 | time (if you need to use Ruby 1.9) visit the
16 | [download](https://rubygems.org/pages/download) page.
17 |
18 | If you want to see how to require files from a gem, skip ahead to [What is a
19 | gem](/what-is-a-gem)
20 |
21 | * [Finding Gems](#finding-gems)
22 | * [Installing Gems](#installing-gems)
23 | * [Requiring Code](#requiring-code)
24 | * [Listing Installed Gems](#listing-installed-gems)
25 | * [Uninstalling Gems](#uninstalling-gems)
26 | * [Viewing Documentation](#viewing-documentation)
27 | * [Fetching and Unpacking Gems](#fetching-and-unpacking-gems)
28 | * [Further Reading](#further-reading)
29 |
30 | Finding Gems
31 | ------------
32 |
33 | The `search` command lets you find remote gems by name. You can use regular
34 | expression characters in your query:
35 |
36 | $ gem search ^rails
37 |
38 | *** REMOTE GEMS ***
39 |
40 | rails (4.0.0)
41 | rails-3-settings (0.1.1)
42 | rails-action-args (0.1.1)
43 | rails-admin (0.0.0)
44 | rails-ajax (0.2.0.20130731)
45 | [...]
46 |
47 | If you see a gem you want more information on you can add the details option.
48 | You'll want to do this with a small number of gems, though, as listing gems
49 | with details requires downloading more files:
50 |
51 | $ gem search ^rails$ -d
52 |
53 | *** REMOTE GEMS ***
54 |
55 | rails (4.0.0)
56 | Author: David Heinemeier Hansson
57 | Homepage: http://www.rubyonrails.org
58 |
59 | Full-stack web application framework.
60 |
61 | You can also search for gems on rubygems.org such as [this search for
62 | rake](https://rubygems.org/search?utf8=✓&query=rake)
63 |
64 | Installing Gems
65 | ---------------
66 |
67 | The `install` command downloads and installs the gem and any necessary
68 | dependencies then builds documentation for the installed gems.
69 |
70 | $ gem install drip
71 | Fetching: rbtree-0.4.1.gem (100%)
72 | Building native extensions. This could take a while...
73 | Successfully installed rbtree-0.4.1
74 | Fetching: drip-0.0.2.gem (100%)
75 | Successfully installed drip-0.0.2
76 | Parsing documentation for rbtree-0.4.1
77 | Installing ri documentation for rbtree-0.4.1
78 | Parsing documentation for drip-0.0.2
79 | Installing ri documentation for drip-0.0.2
80 | Done installing documentation for rbtree, drip after 0 seconds
81 | 2 gems installed
82 |
83 | Here the drip command depends upon the rbtree gem which has an extension. Ruby
84 | installs the dependency rbtree and builds its extension, installs the drip gem,
85 | then builds documentation for the installed gems.
86 |
87 | You can disable documentation generation using the `--no-doc` argument when
88 | installing gems.
89 |
90 | Requiring code
91 | --------------
92 |
93 | RubyGems modifies your Ruby load path, which controls how your Ruby code is
94 | found by the `require` statement. When you `require` a gem, really you're just
95 | placing that gem's `lib` directory onto your `$LOAD_PATH`. Let's try this out
96 | in `irb` and get some help from the `pretty_print` library included with Ruby.
97 |
98 | *Tip: Passing `-r` to
99 | `irb` will automatically require a library when irb is loaded.*
100 |
101 | % irb -rpp
102 | >> pp $LOAD_PATH
103 | [".../lib/ruby/site_ruby/1.9.1",
104 | ".../lib/ruby/site_ruby",
105 | ".../lib/ruby/vendor_ruby/1.9.1",
106 | ".../lib/ruby/vendor_ruby",
107 | ".../lib/ruby/1.9.1",
108 | "."]
109 |
110 | By default you have just a few system directories on the load path and the Ruby
111 | standard libraries. To add the awesome_print directories to the load path,
112 | you can require one of its files:
113 |
114 | % irb -rpp
115 | >> require 'ap'
116 | => true
117 | >> pp $LOAD_PATH.first
118 | ".../gems/awesome_print-1.0.2/lib"
119 |
120 | Note: For Ruby 1.8 you must `require 'rubygems'` before requiring any gems.
121 |
122 | Once you've required `ap`, RubyGems automatically places its
123 | `lib` directory on the `$LOAD_PATH`.
124 |
125 | That's basically it for what's in a gem. Drop Ruby code into `lib`, name a
126 | Ruby file the same as your gem (for the gem "freewill" the file should be
127 | `freewill.rb`, see also [name your gem](/name-your-gem)) and it's loadable by
128 | RubyGems.
129 |
130 | The `lib` directory itself normally contains only one `.rb` file and a
131 | directory with the same name as the gem which contains the rest of the files.
132 |
133 | For example:
134 |
135 | % tree freewill/
136 | freewill/
137 | └── lib/
138 | ├── freewill/
139 | │ ├── user.rb
140 | │ ├── widget.rb
141 | │ └── ...
142 | └── freewill.rb
143 |
144 | Listing Installed Gems
145 | ----------------------
146 |
147 | The `list` command shows your locally installed gems:
148 |
149 | $ gem list
150 |
151 | *** LOCAL GEMS ***
152 |
153 | bigdecimal (1.2.0)
154 | drip (0.0.2)
155 | io-console (0.4.2)
156 | json (1.7.7)
157 | minitest (4.3.2)
158 | psych (2.0.0)
159 | rake (0.9.6)
160 | rbtree (0.4.1)
161 | rdoc (4.0.0)
162 | test-unit (2.0.0.0)
163 |
164 | (Ruby ships with some gems by default, bigdecimal, io-console, json, minitest,
165 | psych, rake, rdoc, test-unit for ruby 2.0.0).
166 |
167 | Uninstalling Gems
168 | -----------------
169 |
170 | The `uninstall` command removes the gems you have installed.
171 |
172 | $ gem uninstall drip
173 | Successfully uninstalled drip-0.0.2
174 |
175 | If you uninstall a dependency of a gem RubyGems will ask you for confirmation.
176 |
177 | $ gem uninstall rbtree
178 |
179 | You have requested to uninstall the gem:
180 | rbtree-0.4.1
181 |
182 | drip-0.0.2 depends on rbtree (>= 0)
183 | If you remove this gem, these dependencies will not be met.
184 | Continue with Uninstall? [yN] n
185 | ERROR: While executing gem ... (Gem::DependencyRemovalException)
186 | Uninstallation aborted due to dependent gem(s)
187 |
188 | Viewing Documentation
189 | ---------------------
190 |
191 | You can view the documentation for your installed gems with `ri`:
192 |
193 | $ ri RBTree
194 | RBTree < MultiRBTree
195 |
196 | (from gem rbtree-0.4.0)
197 | -------------------------------------------
198 | A sorted associative collection that cannot
199 | contain duplicate keys. RBTree is a
200 | subclass of MultiRBTree.
201 | -------------------------------------------
202 |
203 | You can view the documentation for your installed gems in your browser with
204 | the `server` command:
205 |
206 | $ gem server
207 | Server started at http://0.0.0.0:8808
208 | Server started at http://[::]:8808
209 |
210 | You can access this documentation at http://localhost:8808
211 |
212 | Fetching and Unpacking Gems
213 | ---------------------------
214 |
215 | If you wish to audit a gem's contents without installing it you can use the
216 | `fetch` command to download the .gem file then extract its contents with the
217 | `unpack` command.
218 |
219 | $ gem fetch malice
220 | Fetching: malice-13.gem (100%)
221 | Downloaded malice-13
222 | $ gem unpack malice-13.gem
223 | Fetching: malice-13.gem (100%)
224 | Unpacked gem: '.../malice-13'
225 | $ more malice-13/README
226 |
227 | Malice v. 13
228 |
229 | DESCRIPTION
230 |
231 | A small, malicious library.
232 |
233 | [...]
234 | $ rm -r malice-13*
235 |
236 | You can also unpack a gem you have installed, modify a few files, then use the
237 | modified gem in place of the installed one:
238 |
239 | $ gem unpack rake
240 | Unpacked gem: '.../rake-10.1.0'
241 | $ vim rake-10.1.0/lib/rake/...
242 | $ ruby -I rake-10.1.0/lib -S rake some_rake_task
243 | [...]
244 |
245 | The `-I` argument adds your unpacked rake to the ruby `$LOAD_PATH` which
246 | prevents RubyGems from loading the gem version (or the default version). The
247 | `-S` argument finds `rake` in the shell's `$PATH` so you don't have to type out
248 | the full path.
249 |
250 | Further Reading
251 | ---------------
252 |
253 | This guide only shows the basics of using the `gem` command. For information
254 | on what's inside a gem and how to use one you've installed see the next
255 | section, [What is a gem](/what-is-a-gem). For a complete reference of gem
256 | commands see the [Command Reference](/command-reference).
257 |
--------------------------------------------------------------------------------
/_layouts/default.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ page.title }} - RubyGems Guides
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
18 |
29 |
30 |
31 |
32 |
35 |
36 |
37 |
40 |
41 |
42 |
43 |
44 |
69 |
70 |
71 |
72 |
73 | Guides
74 |
75 |
76 |
96 |
97 |
98 |
99 | {{ content }}
100 |
101 |
102 |
103 |
104 |
105 |
106 | Previous
107 |
108 |
109 | Next
110 |
111 |
112 |
113 |
114 |
115 |
170 |
171 |
182 |
183 |
184 |
--------------------------------------------------------------------------------
/gems-with-extensions.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Gems with Extensions
4 | url: /gems-with-extensions
5 | previous: /make-your-own-gem
6 | next: /name-your-gem
7 | alias: /c-extensions
8 | ---
9 |
10 | Creating a gem that includes an extension that is built at install time.
11 |
12 | Many gems use extensions to wrap libraries that are written in C with a ruby
13 | wrapper. Examples include [nokogiri](https://rubygems.org/gems/nokogiri) which
14 | wraps [libxml2 and libxslt](http://www.xmlsoft.org),
15 | [pg](https://rubygems.org/gems/pg) which is an interface to the [PostgreSQL
16 | database](http://www.postgresql.org) and the
17 | [mysql](https://rubygems.org/gems/mysql) and
18 | [mysql2](https://rubygems.org/gems/mysql2) gems which provide an interface to
19 | the [MySQL database](http://www.mysql.com).
20 |
21 | Creating a gem that uses an extension involves several steps. This guide will
22 | focus on what you should put in your gem specification to make this as easy and
23 | maintainable as possible. The extension in this guide will wrap `malloc()` and
24 | `free()` from the C standard library.
25 |
26 | Gem layout
27 | ----------
28 |
29 | Every gem should start with a Rakefile which contains the tasks needed by
30 | developers to work on the gem. The files for the extension should go in the
31 | `ext/` directory in a directory matching the extension's name. For this
32 | example we'll use "my_malloc" for the name.
33 |
34 | Some extensions will be partially written in C and partially written in ruby.
35 | If you are going to support multiple languages, such as C and Java extensions,
36 | you should put the C-specific ruby files under the `ext/` directory as well in a
37 | `lib/` directory.
38 |
39 | Rakefile
40 | ext/my_malloc/extconf.rb # extension configuration
41 | ext/my_malloc/my_malloc.c # extension source
42 | lib/my_malloc.rb # generic features
43 |
44 | When the extension is built the files in `ext/my_malloc/lib/` will be installed
45 | into the `lib/` directory for you.
46 |
47 | extconf.rb
48 | ----------
49 |
50 | The extconf.rb configures a Makefile that will build your extension based. The
51 | extconf.rb must check for the necessary functions, macros and shared libraries
52 | your extension depends upon. The extconf.rb must exit with an error if any of
53 | these are missing.
54 |
55 | Here is an extconf.rb that checks for `malloc()` and `free()` and creates a
56 | Makefile that will install the built extension at `lib/my_malloc/my_malloc.so`:
57 |
58 | require "mkmf"
59 |
60 | abort "missing malloc()" unless have_func "malloc"
61 | abort "missing free()" unless have_func "free"
62 |
63 | create_makefile "my_malloc/my_malloc"
64 |
65 | See the [mkmf documentation][mkmf.rb] and [README.EXT][README.EXT] for further
66 | information about creating an extconf.rb and for documentation on these
67 | methods.
68 |
69 | C Extension
70 | -----------
71 |
72 | The C extension that wraps `malloc()` and `free()` goes in
73 | `ext/my_malloc/my_malloc.c`. Here's the listing:
74 |
75 | #include
76 |
77 | struct my_malloc {
78 | size_t size;
79 | void *ptr;
80 | };
81 |
82 | static void
83 | my_malloc_free(void *p) {
84 | struct my_malloc *ptr = p;
85 |
86 | if (ptr->size > 0)
87 | free(ptr->ptr);
88 | }
89 |
90 | static VALUE
91 | my_malloc_alloc(VALUE klass) {
92 | VALUE obj;
93 | struct my_malloc *ptr;
94 |
95 | obj = Data_Make_Struct(klass, struct my_malloc, NULL, my_malloc_free, ptr);
96 |
97 | ptr->size = 0;
98 | ptr->ptr = NULL;
99 |
100 | return obj;
101 | }
102 |
103 | static VALUE
104 | my_malloc_init(VALUE self, VALUE size) {
105 | struct my_malloc *ptr;
106 | size_t requested = NUM2SIZET(size);
107 |
108 | if (0 == requested)
109 | rb_raise(rb_eArgError, "unable to allocate 0 bytes");
110 |
111 | Data_Get_Struct(self, struct my_malloc, ptr);
112 |
113 | ptr->ptr = malloc(requested);
114 |
115 | if (NULL == ptr->ptr)
116 | rb_raise(rb_eNoMemError, "unable to allocate %ld bytes", requested);
117 |
118 | ptr->size = requested;
119 |
120 | return self;
121 | }
122 |
123 | static VALUE
124 | my_malloc_release(VALUE self) {
125 | struct my_malloc *ptr;
126 |
127 | Data_Get_Struct(self, struct my_malloc, ptr);
128 |
129 | if (0 == ptr->size)
130 | return self;
131 |
132 | ptr->size = 0;
133 | free(ptr->ptr);
134 |
135 | return self;
136 | }
137 |
138 | void
139 | Init_my_malloc(void) {
140 | VALUE cMyMalloc;
141 |
142 | cMyMalloc = rb_const_get(rb_cObject, rb_intern("MyMalloc"));
143 |
144 | rb_define_alloc_func(cMyMalloc, my_malloc_alloc);
145 | rb_define_method(cMyMalloc, "initialize", my_malloc_init, 1);
146 | rb_define_method(cMyMalloc, "free", my_malloc_release, 0);
147 | }
148 |
149 | This extension is simple with just a few parts:
150 |
151 | * `struct my_malloc` to hold the allocated memory
152 | * `my_malloc_free()` to free the allocated memory after garbage collection
153 | * `my_malloc_alloc()` to create the ruby wrapper object
154 | * `my_malloc_init()` to allocate memory from ruby
155 | * `my_malloc_release()` to free memory from ruby
156 | * `Init_my_malloc()` to register the functions in the `MyMalloc` class.
157 |
158 | You can test building the extension as follows:
159 |
160 | $ cd ext/my_malloc
161 | $ ruby extconf.rb
162 | checking for malloc()... yes
163 | checking for free()... yes
164 | creating Makefile
165 | $ make
166 | compiling my_malloc.c
167 | linking shared-object my_malloc.bundle
168 | $ cd ../..
169 | $ ruby -Ilib:ext -r my_malloc -e "p MyMalloc.new(5).free"
170 | #
171 |
172 | But this will get tedious after a while. Let's automate it!
173 |
174 | rake-compiler
175 | -------------
176 |
177 | [rake-compiler][rake-compiler] is a set of rake
178 | tasks for automating extension building. rake-compiler can be used with C or
179 | Java extensions in the same project (nokogiri uses it this way).
180 |
181 | Adding rake-compiler is very simple:
182 |
183 | require "rake/extensiontask"
184 |
185 | Rake::ExtensionTask.new "my_malloc" do |ext|
186 | ext.lib_dir = "lib/my_malloc"
187 | end
188 |
189 | Now you can build the extension with `rake compile` and hook the compile task
190 | into other tasks (such as tests).
191 |
192 | Setting `lib_dir` places the shared library in `lib/my_malloc/my_malloc.so` (or
193 | `.bundle` or `.dll`). This allows the top-level file for the gem to be a ruby
194 | file. This allows you to write the parts that are best suited to ruby in ruby.
195 |
196 | For example:
197 |
198 | class MyMalloc
199 |
200 | VERSION = "1.0"
201 |
202 | end
203 |
204 | require "my_malloc/my_malloc"
205 |
206 | Setting the `lib_dir` also allows you to build a gem that contains pre-built
207 | extensions for multiple versions of ruby. (An extension for Ruby 1.9.3 cannot
208 | be used with an extension for Ruby 2.0.0). `lib/my_malloc.rb` can pick the
209 | correct shared library to install.
210 |
211 | Gem specification
212 | -----------------
213 |
214 | The final step to building the gem is adding the extconf.rb to the extensions
215 | list in the gemspec:
216 |
217 | Gem::Specification.new "my_malloc", "1.0" do |s|
218 | # [...]
219 |
220 | s.extensions = %w[ext/my_malloc/extconf.rb]
221 | end
222 |
223 | Now you can build and release the gem!
224 |
225 | Extension Naming
226 | ----------------
227 |
228 | To avoid unintended interactions between gems, it's a good idea for each gem to
229 | keep all of its files in a single directory. Here are the recommendations for
230 | a gem with the name ``:
231 |
232 | 1. `ext/` is the directory that contains the source files and
233 | `extconf.rb`
234 | 2. `ext//.c` is the main source file (there may be others)
235 | 3. `ext//.c` contains a function `Init_`. (The name
236 | following `Init_` function must exactly match the name of the extension for
237 | it to be loadable by require.)
238 | 4. `ext//extconf.rb` calls `create_makefile('/')` only when
239 | the all the pieces needed to compile the extension are present.
240 | 5. The gemspec sets `extensions = ['ext//extconf.rb']` and includes any
241 | of the necessary extension source files in the `files` list.
242 | 6. `lib/.rb` contains `require '/'` which loads the C
243 | extension
244 |
245 | Further Reading
246 | ---------------
247 |
248 | * [my_malloc](https://github.com/rubygems/guides/tree/my_malloc) contains the
249 | source for this extension with some additional comments.
250 | * [README.EXT][README.EXT] describes in greater detail how to build extensions
251 | in ruby
252 | * [MakeMakefile][mkmf.rb] contains documentation for mkmf.rb, the library
253 | extconf.rb uses to detect ruby and C library features
254 | * [rake-compiler][rake-compiler] integrates building C and Java extensions into
255 | your Rakefile in a smooth manner.
256 | * [Writing C extensions part
257 | 1](http://tenderlovemaking.com/2009/12/18/writing-ruby-c-extensions-part-1.html)
258 | and [part 2](http://tenderlovemaking.com/2010/12/11/writing-ruby-c-extensions-part-2.html))
259 | by Aaron Patterson
260 | * Interfaces to C libraries can be written using ruby and
261 | [fiddle](http://ruby-doc.org/stdlib-2.0/libdoc/fiddle/rdoc/Fiddle.html) (part
262 | of the standard library) or [ruby-ffi](https://github.com/ffi/ffi)
263 |
264 | [README.EXT]: https://github.com/ruby/ruby/blob/trunk/README.EXT
265 | [mkmf.rb]: http://ruby-doc.org/stdlib-2.0/libdoc/mkmf/rdoc/MakeMakefile.html
266 | [rake-compiler]: https://github.com/luislavena/rake-compiler
267 |
268 |
--------------------------------------------------------------------------------
/stylesheets/_flutie.scss:
--------------------------------------------------------------------------------
1 | /*
2 | html5doctor.com Reset Stylesheet (Eric Meyer's Reset Reloaded + HTML5 baseline)
3 | v1.4 2009-07-27 | Authors: Eric Meyer & Richard Clark
4 | html5doctor.com/html-5-reset-stylesheet/
5 | */
6 | html, body, div, span, object, iframe,
7 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
8 | abbr, address, cite, code,
9 | del, dfn, em, img, ins, kbd, q, samp,
10 | small, strong, sub, sup, var,
11 | b, i,
12 | dl, dt, dd, ol, ul, li,
13 | fieldset, form, label, legend,
14 | table, caption, tbody, tfoot, thead, tr, th, td,
15 | article, aside, canvas, details, figcaption, figure,
16 | footer, header, hgroup, menu, nav, section, summary,
17 | time, mark, audio, video {
18 | margin: 0;
19 | padding: 0;
20 | border: 0;
21 | outline: 0;
22 | font-size: 100%;
23 | vertical-align: baseline;
24 | background: transparent; }
25 |
26 | article, aside, details, figcaption, figure,
27 | footer, header, hgroup, menu, nav, section {
28 | display: block; }
29 |
30 | nav ul {
31 | list-style: none; }
32 |
33 | blockquote, q {
34 | quotes: none; }
35 |
36 | blockquote:before, blockquote:after,
37 | q:before, q:after {
38 | content: '';
39 | content: none; }
40 |
41 | a {
42 | margin: 0;
43 | padding: 0;
44 | font-size: 100%;
45 | vertical-align: baseline;
46 | background: transparent; }
47 |
48 | ins {
49 | background-color: #ff9;
50 | color: #000;
51 | text-decoration: none; }
52 |
53 | mark {
54 | background-color: #ff9;
55 | color: #000;
56 | font-style: italic;
57 | font-weight: bold; }
58 |
59 | del {
60 | text-decoration: line-through; }
61 |
62 | abbr[title], dfn[title] {
63 | cursor: help; }
64 |
65 | /* tables still need cellspacing="0" in the markup */
66 | table {
67 | border-collapse: collapse;
68 | border-spacing: 0; }
69 |
70 | hr {
71 | display: block;
72 | height: 1px;
73 | border: 0;
74 | border-top: 1px solid #ccc;
75 | margin: 1em 0;
76 | padding: 0; }
77 |
78 | input, select {
79 | vertical-align: middle; }
80 |
81 | body {
82 | color: #222;
83 | font-size: 13px;
84 | font-family: "helvetica neue", arial, helvetica, "lucida grande", sans-serif; }
85 |
86 | h1, h2, h3, h4, h5, h6 {
87 | color: #111;
88 | font-family: "helvetica neue", Helvetica, arial, sans-serif; }
89 |
90 | /* Success, error & notice boxes for messages and errors. */
91 | div.error, div.notice, div.success,
92 | #flash_failure, #flash_success, #flash_notice {
93 | -moz-border-radius: 8px;
94 | -webkit-border-radius: 8px;
95 | border: 1px solid #ddd;
96 | margin-bottom: 1em;
97 | padding: 0.8em; }
98 |
99 | div.error,
100 | #flash_failure {
101 | background: #FBE3E4;
102 | border-color: #FBC2C4;
103 | color: #D12F19; }
104 |
105 | div.error a,
106 | #flash_failure a {
107 | color: #D12F19; }
108 |
109 | div.notice,
110 | #flash_notice {
111 | background: #FFF6BF;
112 | border-color: #FFD324;
113 | color: #817134; }
114 |
115 | div.notice a,
116 | #flash_notice a {
117 | color: #817134; }
118 |
119 | div.success,
120 | #flash_success {
121 | background: #E6EFC2;
122 | border-color: #C6D880;
123 | color: #529214; }
124 |
125 | div.success a,
126 | #flash_success a {
127 | color: #529214; }
128 |
129 | /* Misc classes and elements */
130 | /* Use a .box to create a padded box inside a column. */
131 | .box {
132 | background: #eee;
133 | margin-bottom: 1.5em;
134 | padding: 1.5em; }
135 |
136 | /* Use this to create a horizontal ruler across a column. */
137 | hr {
138 | background: #ddd;
139 | border: none;
140 | clear: both;
141 | color: #ddd;
142 | float: none;
143 | height: 1px;
144 | margin: 0 0 1.4em;
145 | width: 100%; }
146 |
147 | hr.space {
148 | background: #fff;
149 | color: #fff; }
150 |
151 | /* for image replacement */
152 | .ir {
153 | background-repeat: no-repeat;
154 | direction: ltr;
155 | display: block;
156 | overflow: hidden;
157 | text-align: left;
158 | text-indent: -999em; }
159 |
160 | /* Hide for both screenreaders and browsers
161 | css-discuss.incutio.com/wiki/Screenreader_Visibility */
162 | .hidden {
163 | display: none;
164 | visibility: hidden; }
165 |
166 | /* Hide only visually, but have it available for screenreaders
167 | www.webaim.org/techniques/css/invisiblecontent/ & j.mp/visuallyhidden */
168 | .visuallyhidden {
169 | clip: rect(1px 1px 1px 1px);
170 | /* IE6, IE7 */
171 | clip: rect(1px, 1px, 1px, 1px);
172 | position: absolute !important; }
173 |
174 | /* Hide visually and from screenreaders, but maintain layout */
175 | .invisible {
176 | visibility: hidden; }
177 |
178 | /* >> The Magnificent CLEARFIX: Updated to prevent margin-collapsing on child elements << j.mp/bestclearfix */
179 | .clearfix:before,
180 | .clearfix:after {
181 | content: "\0020";
182 | display: block;
183 | height: 0;
184 | visibility: hidden; }
185 |
186 | .clearfix:after {
187 | clear: both; }
188 |
189 | /* Fix clearfix: blueprintcss.lighthouseapp.com/projects/15318/tickets/5-extra-margin-padding-bottom-of-page */
190 | .clearfix {
191 | zoom: 1; }
192 |
193 | .ie7 img {
194 | -ms-interpolation-mode: bicubic; }
195 |
196 | @media print {
197 | * {
198 | background: transparent !important;
199 | color: #444 !important;
200 | text-shadow: none !important; }
201 |
202 | a, a:visited {
203 | color: #444 !important;
204 | text-decoration: underline; }
205 |
206 | a:after {
207 | content: " (" attr(href) ")"; }
208 |
209 | abbr:after {
210 | content: " (" attr(title) ")"; }
211 |
212 | .ir a:after {
213 | content: ""; }
214 |
215 | /* Don't show links for images */
216 | pre, blockquote {
217 | border: 1px solid #999;
218 | page-break-inside: avoid; }
219 |
220 | thead {
221 | display: table-header-group; }
222 |
223 | /* css-discuss.incutio.com/wiki/Printing_Tables */
224 | tr, img {
225 | page-break-inside: avoid; }
226 |
227 | @page {
228 | margin: 0.5cm; }
229 |
230 | p, h2, h3 {
231 | orphans: 3;
232 | widows: 3; }
233 |
234 | h2, h3 {
235 | page-break-after: avoid; } }
236 |
237 | /* Headings */
238 | h1, h2, h3, h4, h5, h6 {
239 | font-weight: bold; }
240 |
241 | h1 {
242 | font-size: 2.2em;
243 | line-height: 1;
244 | margin-bottom: 0.25em; }
245 |
246 | h2 {
247 | font-size: 1.6em;
248 | line-height: 1.1;
249 | margin-bottom: 0.25em; }
250 |
251 | h3 {
252 | font-size: 1.3em;
253 | line-height: 1;
254 | margin-bottom: 0.25em; }
255 |
256 | h4 {
257 | font-size: 1.1em;
258 | line-height: 1.25;
259 | margin-bottom: 0.25em; }
260 |
261 | h5 {
262 | font-size: 1em;
263 | margin-bottom: 0.25em; }
264 |
265 | h6 {
266 | font-size: 1em;
267 | margin-bottom: 0.25em; }
268 |
269 | /* Text elements */
270 | p {
271 | margin-bottom: 0.5em; }
272 |
273 | p.last {
274 | margin-bottom: 0; }
275 |
276 | p img {
277 | margin: 1em 1em 1em 0;
278 | padding: 0; }
279 |
280 | /* Use this if the image is at the top of the . */
281 | p img.top {
282 | margin-top: 0; }
283 |
284 | img {
285 | margin: 0; }
286 |
287 | abbr, acronym {
288 | border-bottom: 1px dotted #666;
289 | cursor: help; }
290 |
291 | address {
292 | font-style: italic;
293 | margin-top: 1.5em; }
294 |
295 | del {
296 | color: #666; }
297 |
298 | a, a:link {
299 | color: #1a4882;
300 | text-decoration: underline; }
301 |
302 | a:visited {
303 | color: #1a4882; }
304 |
305 | a:hover {
306 | color: #052246; }
307 |
308 | a:active,
309 | a:focus {
310 | color: #1a4882; }
311 |
312 | .avatars a:link {
313 | text-decoration: none; }
314 |
315 | blockquote {
316 | border-left: 4px solid #d1d1d1;
317 | color: #666;
318 | font-style: italic;
319 | margin: 1.5em 0;
320 | padding-left: 1em; }
321 |
322 | strong {
323 | font-weight: bold; }
324 |
325 | em,
326 | dfn {
327 | font-style: italic; }
328 |
329 | dfn {
330 | font-weight: bold; }
331 |
332 | pre, code {
333 | margin: 1.5em 0;
334 | white-space: pre;
335 | /* CSS2 */
336 | white-space: pre-wrap;
337 | /* CSS 2.1 */
338 | word-wrap: break-word;
339 | /* IE */ }
340 |
341 | pre, code, tt {
342 | font: 1em 'andale mono', 'monotype.com', 'lucida console', monospace;
343 | line-height: 1.5; }
344 |
345 | pre.code {
346 | background: #000;
347 | color: #fff;
348 | padding: 20px; }
349 |
350 | tt {
351 | display: block;
352 | line-height: 1.5;
353 | margin: 1.5em 0; }
354 |
355 | /* Forms */
356 | /*removes dotted outline on submit buttons when clicking in firefox */
357 | input[type="submit"]::-moz-focus-inner {
358 | border: none; }
359 |
360 | form ol {
361 | list-style: none;
362 | margin: 0 0 1em 0; }
363 |
364 | form ol ol {
365 | margin-left: 0; }
366 |
367 | form ol li {
368 | list-style-position: outside;
369 | margin: 0 0 1em 0; }
370 |
371 | /*list-style-position fixes IE label margin bug*/
372 | form ol ol li {
373 | list-style-position: outside;
374 | margin: 0 0 .25em 0; }
375 |
376 | form ol li.error input {
377 | background: #FBE3E4; }
378 |
379 | p.inline-errors {
380 | color: #D12F19; }
381 |
382 | form ol li.file {
383 | background: #e1e1e1;
384 | border: 1px solid #c8c8c8;
385 | padding: 10px; }
386 |
387 | form abbr {
388 | border-bottom: 0; }
389 |
390 | label {
391 | display: block; }
392 |
393 | .required label {
394 | font-weight: bold; }
395 |
396 | .checkbox_field label,
397 | .radio_field label {
398 | font-weight: normal; }
399 |
400 | a.cancel {
401 | color: #7d0d0d; }
402 |
403 | .inline-hints {
404 | color: #666;
405 | font-size: 0.8em;
406 | margin-bottom: 0.25em; }
407 |
408 | /* Fieldsets */
409 | fieldset {
410 | background: #f1f1f1;
411 | border: 1px solid #e3e3e3;
412 | margin: 0 0 1.5em 0;
413 | padding: 1.5em 1.5em 1em 1.5em; }
414 |
415 | fieldset fieldset,
416 | fieldset fieldset fieldset {
417 | border: 0;
418 | padding: 0; }
419 |
420 | legend {
421 | font-weight: bold; }
422 |
423 | .ie6 legend, .ie7 legend {
424 | margin-left: -7px; }
425 |
426 | fieldset.buttons {
427 | background: inherit;
428 | border: 0;
429 | padding: 0; }
430 |
431 | fieldset.buttons li {
432 | display: inline; }
433 |
434 | .radio fieldset {
435 | margin: 0;
436 | padding: 0; }
437 |
438 | /* Text fields */
439 | input[type="color"],
440 | input[type="date"],
441 | input[type="datetime"],
442 | input[type="datetime-local"],
443 | input[type="email"],
444 | input[type="month"],
445 | input[type="number"],
446 | input[type="password"],
447 | input[type="range"],
448 | input[type="search"],
449 | input[type="tel"],
450 | input[type="text"],
451 | input[type="time"],
452 | input[type="url"],
453 | input[type="week"] {
454 | font-size: inherit;
455 | padding: 3px 2px;
456 | width: 300px; }
457 |
458 | .ie6 input {
459 | vertical-align: text-bottom; }
460 |
461 | input[disabled='disabled'] {
462 | background-color: #fcfcfc;
463 | cursor: default; }
464 |
465 | input[type="checkbox"] {
466 | margin: 0 3px 0 0;
467 | position: relative;
468 | top: -2px;
469 | vertical-align: middle; }
470 |
471 | .ie7 input[type="checkbox"] {
472 | vertical-align: baseline; }
473 |
474 | input[type="radio"] {
475 | margin: 0 3px 0 0;
476 | position: relative;
477 | top: -2px;
478 | vertical-align: middle; }
479 |
480 | .check_boxes label {
481 | display: inline;
482 | padding: 0;
483 | vertical-align: middle; }
484 |
485 | .radio label {
486 | padding: 0; }
487 |
488 | /* Textareas */
489 | textarea {
490 | font-size: inherit;
491 | height: 200px;
492 | margin: 0 0.5em 0.5em 0;
493 | padding: 5px;
494 | width: 440px;
495 | overflow: auto; }
496 |
497 | /* Select fields */
498 | fieldset .select select {
499 | width: 200px;
500 | font-size: 0.9em; }
501 |
502 | optgroup {
503 | margin: 0 0 .5em 0; }
504 |
505 | /* Date & Time */
506 | form ol li.date ol li,
507 | form ol li.time ol li {
508 | display: inline; }
509 |
510 | form ol li.datetime ol li {
511 | display: inline-block; }
512 |
513 | form ol li.datetime select,
514 | form ol li.date select,
515 | form ol li.time select {
516 | display: inline;
517 | width: auto; }
518 |
519 | form ol li.date label,
520 | form ol li.time label {
521 | display: none; }
522 |
523 | /* Tables */
524 | table {
525 | margin-bottom: 2em;
526 | width: 100%; }
527 |
528 | th {
529 | border-bottom: 2px solid #ccc;
530 | font-weight: bold;
531 | text-align: left; }
532 |
533 | td {
534 | border-bottom: 1px solid #ddd; }
535 |
536 | caption, th, td {
537 | padding: 4px 10px 4px 0; }
538 |
539 | caption {
540 | background: #f1f1f1;
541 | margin-bottom: 1em;
542 | padding: 10px 0; }
543 |
544 | tr, td, th {
545 | vertical-align: middle; }
546 |
547 | /* Use this if you use span-x classes on th/td. */
548 | table .last {
549 | padding-right: 0; }
550 |
551 | /* Lists */
552 | ul, ol {
553 | list-style-position: inside;
554 | margin-bottom: 1.5em; }
555 |
556 | ul {
557 | list-style-type: disc; }
558 |
559 | ol {
560 | list-style-type: decimal; }
561 |
562 | dl {
563 | line-height: 1.4;
564 | margin-bottom: 1.5em; }
565 |
566 | dl dt {
567 | font-weight: bold;
568 | margin-top: 0.5em; }
569 |
570 | dl dd {
571 | margin-bottom: 0em; }
572 |
573 | dd {
574 | margin-left: 0.5em; }
575 |
576 | li {
577 | line-height: 1.4; }
578 |
579 | ol ol, ol ul, ul ul, ul ol {
580 | margin-left: 1em; }
581 |
--------------------------------------------------------------------------------
/patterns.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Patterns
4 | url: /patterns
5 | previous: /security
6 | next: /specification-reference
7 | ---
8 |
9 | Common practices to make your gem users' and other developers' lives easier.
10 |
11 | * [Consistent naming](#consistent-naming)
12 | * [Semantic versioning](#semantic-versioning)
13 | * [Declaring dependencies](#declaring-dependencies)
14 | * [Loading code](#loading-code)
15 | * [Prerelease gems](#prerelease-gems)
16 |
17 | Consistent naming
18 | -----------------
19 |
20 | > There are only two hard things in Computer Science: cache invalidation and naming things.
21 | > -[Phil Karlton](http://martinfowler.com/bliki/TwoHardThings.html)
22 |
23 | ### File names
24 |
25 | Be consistent with how your gem files in `lib` and `bin` are named. The
26 | [hola](https://github.com/qrush/hola) gem from the [make your own
27 | gem](/make-your-own-gem) guide is a great example:
28 |
29 | % tree
30 | .
31 | ├── Rakefile
32 | ├── bin
33 | │ └── hola
34 | ├── hola.gemspec
35 | ├── lib
36 | │ ├── hola
37 | │ │ └── translator.rb
38 | │ └── hola.rb
39 | └── test
40 | └── test_hola.rb
41 |
42 | The executable and the primary file in `lib` are named the same. A developer
43 | can easily jump in and call `require 'hola'` with no problems.
44 |
45 | ### Naming your gem
46 |
47 | Naming your gem is important. Before you pick a name for your gem, do a
48 | quick search on [RubyGems.org](http://rubygems.org) and
49 | [GitHub](https://github.com/search) to see if someone else has taken it. Every
50 | published gem must have a unique name. Be sure to read our [naming
51 | recommendations](/name-your-gem) when you've found a name you like.
52 |
53 | Semantic versioning
54 | -------------------
55 |
56 | A versioning policy is merely a set of simple rules governing how version
57 | numbers are allocated. It can be very simple (e.g. the version number is a
58 | single number starting with 1 and incremented for each successive version), or
59 | it can be really strange (Knuth’s TeX project had version numbers: 3,
60 | 3.1, 3.14, 3.141, 3.1415; each successive version added another digit to PI).
61 |
62 | The RubyGems team urges gem developers to follow the
63 | [Semantic Versioning](http://semver.org) standard for their gem's versions. The
64 | RubyGems library itself does not enforce a strict versioning policy, but using
65 | an "irrational" policy will only be a disservice to those in the community who
66 | use your gems.
67 |
68 | Suppose you have a 'stack' gem that holds a `Stack` class with both `push` and
69 | `pop` functionalty. Your `CHANGELOG` might look like this if you use
70 | semantic versioning:
71 |
72 | * **Version 0.0.1**: The initial `Stack` class is released.
73 | * **Version 0.0.2**: Switched to a linked list implementation because it is
74 | cooler.
75 | * **Version 0.1.0**: Added a `depth` method.
76 | * **Version 1.0.0**: Added `top` and made `pop` return `nil` (`pop` used to
77 | return the old top item).
78 | * **Version 1.1.0**: `push` now returns the value pushed (it used it return
79 | `nil`).
80 | * **Version 1.1.1**: Fixed a bug in the linked list implementation.
81 | * **Version 1.1.2**: Fixed a bug introduced in the last fix.
82 |
83 | Semantic versioning boils down to:
84 |
85 | * **PATCH** `0.0.x` level changes for implementation level detail changes, such
86 | as small bug fixes
87 | * **MINOR** `0.x.0` level changes for any backwards compatible API changes,
88 | such as new functionality/features
89 | * **MAJOR** `x.0.0` level changes for backwards *incompatible* API changes,
90 | such as changes that will break existing users code if they update
91 |
92 | Declaring dependencies
93 | ----------------------
94 |
95 | Gems work with other gems. Here are some tips to make sure they're nice to each
96 | other.
97 |
98 | ### Runtime vs. development
99 |
100 | RubyGems provides two main "types" of dependencies: runtime and development.
101 | Runtime dependencies are what your gem needs to work (such as
102 | [rails](http://rubygems.org/gems/rails) needing
103 | [activesupport](http://rubygems.org/gems/activesupport)).
104 |
105 | Development dependencies are useful for when someone wants to make
106 | modifications to your gem. When you specify development dependencies, another
107 | developer can run `gem install --dev your_gem` and RubyGems will grab both sets
108 | of dependencies (runtime and development). Typical development dependencies
109 | include test frameworks and build systems.
110 |
111 | Setting dependencies in your gemspec is easy. Just use `add_runtime_dependency`
112 | and `add_development_dependency`:
113 |
114 | Gem::Specification.new do |s|
115 | s.name = "hola"
116 | s.version = "2.0.0"
117 | s.add_runtime_dependency "daemons",
118 | ["= 1.1.0"]
119 | s.add_development_dependency "bourne",
120 | [">= 0"]
121 |
122 | ### Don't use `gem` from within your gem
123 |
124 | You may have seen some code like this around to make sure you're using a
125 | specific version of a gem:
126 |
127 | gem "extlib", ">= 1.0.8"
128 | require "extlib"
129 |
130 | It's reasonable for applications that consume gems to use this (though they
131 | could also use a tool like [Bundler](http://bundler.io)). Gems themselves
132 | **should not** do this. They should instead use dependencies in the gemspec so
133 | RubyGems can handle loading the dependency instead of the user.
134 |
135 | ### Pessimistic version constraint
136 |
137 | If your gem properly follows [semantic versioning](http://semver.org) with its
138 | versioning scheme, then other Ruby developers can take advantage of this when
139 | choosing a version constraint to lock down your gem in their application.
140 |
141 | Let's say the following releases of a gem exist:
142 |
143 | * **Version 2.1.0** — Baseline
144 | * **Version 2.2.0** — Introduced some new (backward compatible) features.
145 | * **Version 2.2.1** — Removed some bugs
146 | * **Version 2.2.2** — Streamlined your code
147 | * **Version 2.3.0** — More new features (but still backwards compatible).
148 | * **Version 3.0.0** — Reworked the interface. Code written to version 2.x might
149 | not work.
150 |
151 | Someone who wants to use your gem has determined that version 2.2.0 works with
152 | their software, but version 2.1.0 doesn't have a feature they need. Adding a
153 | dependency in a gem (or a `Gemfile` from Bundler) might look like:
154 |
155 | # gemspec
156 | spec.add_runtime_dependency 'library',
157 | '>= 2.2.0'
158 |
159 | # bundler
160 | gem 'library', '>= 2.2.0'
161 |
162 | This is an "optimistic" version constraint. It's saying that all changes from
163 | 2.x on *will* work with my software, but for version 3.0.0 this will not be
164 | true.
165 |
166 | The alternative here is to be "pessimistic". This explicitly excludes the
167 | version that might break your code.
168 |
169 | # gemspec
170 | spec.add_runtime_dependency 'library',
171 | ['>= 2.2.0', '< 3.0']
172 |
173 | # bundler
174 | gem 'library', '>= 2.2.0', '< 3.0'
175 |
176 | RubyGems provides a shortcut for this, commonly known as the
177 | [twiddle-wakka](http://robots.thoughtbot.com/post/2508037841/twiddle-wakka):
178 |
179 | # gemspec
180 | spec.add_runtime_dependency 'library',
181 | '~> 2.2'
182 |
183 | # bundler
184 | gem 'library', '~> 2.2'
185 |
186 | Notice that we dropped the `PATCH` level of the version number. Had we said
187 | `~> 2.2.0`, that would have been equivalent to `['>= 2.2.0', '< 2.3.0']`.
188 |
189 | If you want to allow use of newer backwards-compatible versions but need a
190 | specific bug fix you can use a compound requirement:
191 |
192 | # gemspec
193 | spec.add_runtime_dependency 'library', '~> 2.2', '>= 2.2.1'
194 |
195 | # bundler
196 | gem 'library', '~> 2.2', '>= 2.2.1'
197 |
198 | The important note to take home here is to be aware others *will* be using
199 | your gems, so guard yourself from potential bugs/failures in future releases
200 | by using `~>` instead of `>=` if at all possible.
201 |
202 | > If you're dealing with a lot of gem dependencies in your application, we
203 | > recommend that you take a look into [Bundler](http://bundler.io) or
204 | > [Isolate](https://github.com/jbarnette/isolate) which do a great job of
205 | > managing a complex version manifest for many gems.
206 |
207 | If you want to allow prereleases and regular releases use a compound
208 | requirement:
209 |
210 | # gemspec
211 | spec.add_runtime_dependency 'library', '>= 2.0.0.a', '< 3'
212 |
213 | Using `~>` with prerelease versions will restrict you to prerelease versions
214 | only.
215 |
216 | ### Requiring RubyGems
217 |
218 | Summary: don't.
219 |
220 | This line...
221 |
222 | require 'rubygems'
223 |
224 | ...should not be necessary in your gem code, since RubyGems is loaded
225 | already when a gem is required. Not having `require 'rubygems'` in your code
226 | means that the gem can be easily used without needing the RubyGems client to
227 | run.
228 |
229 | For more information please check out [Ryan
230 | Tomayko's](http://tomayko.com/writings/require-rubygems-antipattern) original
231 | post about the subject.
232 |
233 | Loading code
234 | ------------
235 |
236 | At its core, RubyGems exists to help you manage Ruby's `$LOAD_PATH`, which is
237 | how the `require` statement picks up new code. There's several things you can
238 | do to make sure you're loading code the right way.
239 |
240 | ### Respect the global load path
241 |
242 | When packaging your gem files, you need to be careful of what is in your `lib`
243 | directory. Every gem you have installed gets its `lib` directory appended onto
244 | your `$LOAD_PATH`. This means any file on the top level of the `lib` directory
245 | could get required.
246 |
247 | For example, let's say we have a `foo` gem with the following structure:
248 |
249 | .
250 | └── lib
251 | ├── foo
252 | │ └── cgi.rb
253 | ├── erb.rb
254 | ├── foo.rb
255 | └── set.rb
256 |
257 | This might seem harmless since your custom `erb` and `set` files are within
258 | your gem. However, this is not harmless, anyone who requires this gem will not
259 | be able to bring in the
260 | [ERB](http://ruby-doc.org/stdlib/libdoc/erb/rdoc/classes/ERB.html) or
261 | [Set](http://www.ruby-doc.org/stdlib/libdoc/set/rdoc/classes/Set.html) classes
262 | provided by Ruby's standard library.
263 |
264 | The best way to get around this is to keep files in a different directory
265 | under `lib`. The usual convention is to be consistent and put them in the same
266 | folder name as your gem's name, for example `lib/foo/cgi.rb`.
267 |
268 | ### Requiring files relative to each other
269 |
270 | Gems should not have to use `__FILE__` to bring in other Ruby files in your
271 | gem. Code like this is surprisingly common in gems:
272 |
273 | require File.join(
274 | File.dirname(__FILE__),
275 | "foo", "bar")
276 |
277 | Or:
278 |
279 | require File.expand_path(File.join(
280 | File.dirname(__FILE__),
281 | "foo", "bar"))
282 |
283 | The fix is simple, just require the file relative to the load path:
284 |
285 | require 'foo/bar'
286 |
287 | Or use require_relative:
288 |
289 | require_relative 'foo/bar'
290 |
291 | The [make your own gem](/make-your-own-gem) guide has a great example of this
292 | behavior in practice, including a working test suite. The code for that gem is
293 | [on GitHub](https://github.com/qrush/hola) as well.
294 |
295 | ### Mangling the load path
296 |
297 | Gems should not change the `$LOAD_PATH` variable. RubyGems manages this for
298 | you. Code like this should not be necessary:
299 |
300 | lp = File.expand_path(File.dirname(__FILE__))
301 | unless $LOAD_PATH.include?(lp)
302 | $LOAD_PATH.unshift(lp)
303 | end
304 |
305 | Or:
306 |
307 | __DIR__ = File.dirname(__FILE__)
308 |
309 | $LOAD_PATH.unshift __DIR__ unless
310 | $LOAD_PATH.include?(__DIR__) ||
311 | $LOAD_PATH.include?(File.expand_path(__DIR__))
312 |
313 | When RubyGems activates a gem, it adds your package's `lib` folder to the
314 | `$LOAD_PATH` ready to be required normally by another lib or application. It
315 | is safe to assume you can then `require` any file in your `lib` folder.
316 |
317 | Prerelease gems
318 | ---------------
319 |
320 | Many gem developers have versions of their gem ready to go out for testing or
321 | "edge" releases before a big gem release. RubyGems supports the concept of
322 | "prerelease" versions, which could be betas, alphas, or anything else that
323 | isn't ready as a regular release.
324 |
325 | Taking advantage of this is easy. All you need is one or more letters in the
326 | gem version. For example, here's what a prerelease gemspec's `version` field
327 | might look like:
328 |
329 | Gem::Specification.new do |s|
330 | s.name = "hola"
331 | s.version = "1.0.0.pre"
332 |
333 | Other prerelease version numbers might include `2.0.0.rc1`, or `1.5.0.beta.3`.
334 | It just has to have a letter in it, and you're set. These gems can then be
335 | installed with the `--pre` flag, like so:
336 |
337 | % gem list factory_girl -r --pre
338 |
339 | *** REMOTE GEMS ***
340 |
341 | factory_girl (2.0.0.beta2, 2.0.0.beta1)
342 | factory_girl_rails (1.1.beta1)
343 |
344 | % gem install factory_girl --pre
345 | Successfully installed factory_girl-2.0.0.beta2
346 | 1 gem installed
347 |
348 | Credits
349 | -------
350 |
351 | Several sources were used for content for this guide:
352 |
353 | * [Rubygems Good Practice](http://yehudakatz.com/2009/07/24/rubygems-good-practice/)
354 | * [Gem Packaging: Best Practices](http://weblog.rubyonrails.org/2009/9/1/gem-packaging-best-practices)
355 |
--------------------------------------------------------------------------------
/stylesheets/application.css.map:
--------------------------------------------------------------------------------
1 | {
2 | "version": 3,
3 | "mappings": "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",
4 | "sources": ["_load.scss","_base.scss","_layout.scss","_type.scss","modules/_footer.scss","modules/_header.scss","modules/_projects.scss","modules/_search.scss","modules/_shared.scss","modules/nav/_nav--paginated.scss","modules/nav/_nav--v.scss"],
5 | "names": [],
6 | "file": "application.css"
7 | }
--------------------------------------------------------------------------------
/contributing.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Contributing to RubyGems
4 | url: /contributing
5 | previous: /resources
6 | next: /faqs
7 | ---
8 |
9 | How you can help make RubyGems and the surrounding ecosystem better.
10 |
11 | Looking to contribute to a RubyGems project? You've come to the right place!
12 | There are many development efforts going on right now, and they could use
13 | your help. Just follow the links below to get started contributing or to contact the
14 | project maintainers.
15 |
16 | * [Core Projects](#core-projects)
17 | * [Ecosystem Projects](#ecosystem-projects)
18 | * [Add Your Own Idea](#add-your-own-idea)
19 |
20 | Core Projects
21 | -------------
22 |
23 | These projects are under the wing of the core [RubyGems team](https://github.com/rubygems/).
24 |
25 | RubyGems
26 |
27 | Ruby's premier packaging system. Bundled with Ruby 1.9+ and available for Ruby 1.8. Any time you run
28 | `gem` at the command line, you're using this project.
29 |
30 |
31 | Issues
32 | Mailing List
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | Code Guidelines:
51 |
52 | * New features should be coupled with tests.
53 | * Ensure that your code blends well with ours (eg, no trailing whitespace, match indentation and coding style).
54 | * Don’t modify the history file or version number.
55 | * If you have any questions, just ask us on IRC in #rubygems or file [an issue][1].
56 |
57 | [0]: https://github.com/rubygems/rubygems
58 | [1]: https://github.com/rubygems/rubygems/issues
59 | [2]: http://help.rubygems.org
60 |
61 | RubyGems.org
62 |
63 | The Ruby community's gem hosting service. Provides a better API for accessing,
64 | deploying, and managing gems along with clear and accessible project pages.
65 |
66 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 | RubyGems Infrastructure
88 |
89 | Chef cookbooks and bootstrap scripts to configure and manage Rubygems.org on AWS.
90 |
91 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 | RubyGems Status
109 |
110 | A simple Rails app to show the status of the rubygems.org infrastructure.
111 |
112 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 | RubyGems Guides
127 |
128 | The central home for RubyGems documentation, including tutorials and reference material.
129 | User-contributed guides are more than welcome and encouraged!
130 |
131 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 | RubyGems Testers
149 |
150 | A community effort to document the test results for various gems,
151 | on various machine architectures.
152 |
153 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 | Gem Whisperer
168 |
169 | An example of how to use [RubyGems.org's
170 | webhooks](http://guides.rubygems.org/rubygems-org-api/#webhook) to listen to every gem being
171 | pushed. Currently powers [m.rubygems.org](http://m.rubygems.org) and
172 | [@rubygems](http://twitter.com/rubygems).
173 |
174 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 | RubyGems.org API Library
189 |
190 | A Ruby implementation of the various API endpoints available on RubyGems.org.
191 | If you're writing a service in Ruby to interact with gems available to the
192 | community, check this out!
193 |
194 |
195 | Issues
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 | RubyGems Mirror
205 |
206 | The current state of mirroring RubyGems is frankly embarrassing. We need
207 | RubyGems to be highly available all over the world, no more excuses! Discussion
208 | is going on in the [rubygems-mirror
209 | wiki](https://github.com/rubygems/rubygems-mirror/wiki/Mirroring-2.0) on how
210 | to improve it.
211 |
212 |
213 | Issues
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 | RubyGems Verification
223 |
224 | A collection of tools and data used for verifying the integrity of gems on rubygems.org based on checksums
225 | collected by third parties.
226 |
227 |
228 | Issues
229 |
230 |
231 | ## Ecosystem Projects
232 |
233 | These projects are outside of the RubyGems core, but work closely with RubyGems to improve the gem experience for everyone.
234 |
235 | Bundler
236 |
237 | Bundler manages an application's dependencies through its entire life across
238 | many machines systematically and repeatably.
239 |
240 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 | Isolate
262 |
263 | A simple gem sandbox that makes sure your application has the exact gem
264 | versions you require. It does not perform dependency resolution like Bundler.
265 |
266 |
267 | Issues
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 | RubyDoc.info
277 |
278 | A fantastic provider of [YARD](http://yardoc.org) documentation for every
279 | RubyGem available. Push a gem, and you get docs created instantly!
280 | RubyGems.org links to this site and it uses [RubyGems.org's
281 | webhooks](http://guides.rubygems.org/rubygems-org-api/#webhook) as well.
282 |
283 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 | Stickler
299 |
300 | Stickler is a great way to run and organize an internal gem server in your
301 | organization. It helps with mirroring gems and providing a gem source to add
302 | internal or proprietary code to.
303 |
304 |
305 | Issues
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 | Geminabox
315 |
316 | Need simple RubyGems hosting? Geminabox can do that! This project provides an
317 | easy to setup way to host RubyGems internally and allow uploading of gems
318 | without much hassle.
319 |
320 |
321 | Issues
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 | Add Your Own Idea
331 | -----------------
332 |
333 | We’d love for your new idea to be on this list. If you’re working on a
334 | RubyGems related project, just [fork this
335 | repo](https://github.com/rubygems/guides) and add the link!
336 |
--------------------------------------------------------------------------------
/CC-LICENSE:
--------------------------------------------------------------------------------
1 | License
2 |
3 | THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
4 |
5 | BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
6 |
7 | 1. Definitions
8 |
9 | 1. "Collective Work" means a work, such as a periodical issue, anthology or encyclopedia, in which the Work in its entirety in unmodified form, along with one or more other contributions, constituting separate and independent works in themselves, are assembled into a collective whole. A work that constitutes a Collective Work will not be considered a Derivative Work (as defined below) for the purposes of this License.
10 | 2. "Creative Commons Compatible License" means a license that is listed at http://creativecommons.org/compatiblelicenses that has been approved by Creative Commons as being essentially equivalent to this License, including, at a minimum, because that license: (i) contains terms that have the same purpose, meaning and effect as the License Elements of this License; and, (ii) explicitly permits the relicensing of derivatives of works made available under that license under this License or either a Creative Commons unported license or a Creative Commons jurisdiction license with the same License Elements as this License.
11 | 3. "Derivative Work" means a work based upon the Work or upon the Work and other pre-existing works, such as a translation, musical arrangement, dramatization, fictionalization, motion picture version, sound recording, art reproduction, abridgment, condensation, or any other form in which the Work may be recast, transformed, or adapted, except that a work that constitutes a Collective Work will not be considered a Derivative Work for the purpose of this License. For the avoidance of doubt, where the Work is a musical composition or sound recording, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered a Derivative Work for the purpose of this License.
12 | 4. "License Elements" means the following high-level license attributes as selected by Licensor and indicated in the title of this License: Attribution, ShareAlike.
13 | 5. "Licensor" means the individual, individuals, entity or entities that offers the Work under the terms of this License.
14 | 6. "Original Author" means the individual, individuals, entity or entities who created the Work.
15 | 7. "Work" means the copyrightable work of authorship offered under the terms of this License.
16 | 8. "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation.
17 |
18 | 2. Fair Use Rights. Nothing in this license is intended to reduce, limit, or restrict any rights arising from fair use, first sale or other limitations on the exclusive rights of the copyright owner under copyright law or other applicable laws.
19 |
20 | 3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below:
21 |
22 | 1. to reproduce the Work, to incorporate the Work into one or more Collective Works, and to reproduce the Work as incorporated in the Collective Works;
23 | 2. to create and reproduce Derivative Works provided that any such Derivative Work, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified.";
24 | 3. to distribute copies or phonorecords of, display publicly, perform publicly, and perform publicly by means of a digital audio transmission the Work including as incorporated in Collective Works;
25 | 4. to distribute copies or phonorecords of, display publicly, perform publicly, and perform publicly by means of a digital audio transmission Derivative Works.
26 | 5.
27 |
28 | For the avoidance of doubt, where the Work is a musical composition:
29 | 1. Performance Royalties Under Blanket Licenses. Licensor waives the exclusive right to collect, whether individually or, in the event that Licensor is a member of a performance rights society (e.g. ASCAP, BMI, SESAC), via that society, royalties for the public performance or public digital performance (e.g. webcast) of the Work.
30 | 2. Mechanical Rights and Statutory Royalties. Licensor waives the exclusive right to collect, whether individually or via a music rights agency or designated agent (e.g. Harry Fox Agency), royalties for any phonorecord You create from the Work ("cover version") and distribute, subject to the compulsory license created by 17 USC Section 115 of the US Copyright Act (or the equivalent in other jurisdictions).
31 | 6. Webcasting Rights and Statutory Royalties. For the avoidance of doubt, where the Work is a sound recording, Licensor waives the exclusive right to collect, whether individually or via a performance-rights society (e.g. SoundExchange), royalties for the public digital performance (e.g. webcast) of the Work, subject to the compulsory license created by 17 USC Section 114 of the US Copyright Act (or the equivalent in other jurisdictions).
32 |
33 | The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. All rights not expressly granted by Licensor are hereby reserved.
34 |
35 | 4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions:
36 |
37 | 1. You may distribute, publicly display, publicly perform, or publicly digitally perform the Work only under the terms of this License, and You must include a copy of, or the Uniform Resource Identifier for, this License with every copy or phonorecord of the Work You distribute, publicly display, publicly perform, or publicly digitally perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of a recipient of the Work to exercise of the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties. When You distribute, publicly display, publicly perform, or publicly digitally perform the Work, You may not impose any technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise of the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collective Work, but this does not require the Collective Work apart from the Work itself to be made subject to the terms of this License. If You create a Collective Work, upon notice from any Licensor You must, to the extent practicable, remove from the Collective Work any credit as required by Section 4(c), as requested. If You create a Derivative Work, upon notice from any Licensor You must, to the extent practicable, remove from the Derivative Work any credit as required by Section 4(c), as requested.
38 | 2. You may distribute, publicly display, publicly perform, or publicly digitally perform a Derivative Work only under: (i) the terms of this License; (ii) a later version of this License with the same License Elements as this License; (iii) either the Creative Commons (Unported) license or a Creative Commons jurisdiction license (either this or a later license version) that contains the same License Elements as this License (e.g. Attribution-ShareAlike 3.0 (Unported)); (iv) a Creative Commons Compatible License. If you license the Derivative Work under one of the licenses mentioned in (iv), you must comply with the terms of that license. If you license the Derivative Work under the terms of any of the licenses mentioned in (i), (ii) or (iii) (the "Applicable License"), you must comply with the terms of the Applicable License generally and with the following provisions: (I) You must include a copy of, or the Uniform Resource Identifier for, the Applicable License with every copy or phonorecord of each Derivative Work You distribute, publicly display, publicly perform, or publicly digitally perform; (II) You may not offer or impose any terms on the Derivative Works that restrict the terms of the Applicable License or the ability of a recipient of the Work to exercise the rights granted to that recipient under the terms of the Applicable License; (III) You must keep intact all notices that refer to the Applicable License and to the disclaimer of warranties; and, (IV) when You distribute, publicly display, publicly perform, or publicly digitally perform the Work, You may not impose any technological measures on the Derivative Work that restrict the ability of a recipient of the Derivative Work from You to exercise the rights granted to that recipient under the terms of the Applicable License. This Section 4(b) applies to the Derivative Work as incorporated in a Collective Work, but this does not require the Collective Work apart from the Derivative Work itself to be made subject to the terms of the Applicable License.
39 | 3. If You distribute, publicly display, publicly perform, or publicly digitally perform the Work (as defined in Section 1 above) or any Derivative Works (as defined in Section 1 above) or Collective Works (as defined in Section 1 above), You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or (ii) if the Original Author and/or Licensor designate another party or parties (e.g. a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; the title of the Work if supplied; to the extent reasonably practicable, the Uniform Resource Identifier, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and, consistent with Section 3(b) in the case of a Derivative Work, a credit identifying the use of the Work in the Derivative Work (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4(c) may be implemented in any reasonable manner; provided, however, that in the case of a Derivative Work or Collective Work, at a minimum such credit will appear, if a credit for all contributing authors of the Derivative Work or Collective Work appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties.
40 |
41 | 5. Representations, Warranties and Disclaimer
42 |
43 | UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND ONLY TO THE EXTENT OF ANY RIGHTS HELD IN THE LICENSED WORK BY THE LICENSOR. THE LICENSOR MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MARKETABILITY, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
44 |
45 | 6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
46 |
47 | 7. Termination
48 |
49 | 1. This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Derivative Works or Collective Works from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License.
50 | 2. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above.
51 |
52 | 8. Miscellaneous
53 |
54 | 1. Each time You distribute or publicly digitally perform the Work (as defined in Section 1 above) or a Collective Work (as defined in Section 1 above), the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License.
55 | 2. Each time You distribute or publicly digitally perform a Derivative Work, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License.
56 | 3. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
57 | 4. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent.
58 | 5. This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You.
59 |
60 |
--------------------------------------------------------------------------------
/make-your-own-gem.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Make your own gem
4 | url: /make-your-own-gem
5 | previous: /what-is-a-gem
6 | next: /gems-with-extensions
7 | ---
8 |
9 | From start to finish, learn how to package your Ruby code in a gem.
10 |
11 |
12 | * [Introduction](#introduction)
13 | * [Your first gem](#your-first-gem)
14 | * [Requiring more files](#requiring-more-files)
15 | * [Adding an executable](#adding-an-executable)
16 | * [Writing tests](#writing-tests)
17 | * [Documenting your code](#documenting-your-code)
18 | * [Wrapup](#wrapup)
19 |
20 | Introduction
21 | ------------
22 |
23 | Creating and publishing your own gem is simple thanks to the tools baked right
24 | into RubyGems. Let’s make a simple “hello world” gem, and feel free to
25 | play along at home! The code for the gem we're going to make here is up
26 | [on GitHub](https://github.com/qrush/hola).
27 |
28 | Your first gem
29 | --------------
30 |
31 | I started with just one Ruby file for my `hola` gem, and the gemspec.
32 | You'll need a new name for yours (maybe `hola_yourusername`) to publish it. Check the Patterns guide for
33 | [basic recommendations](/patterns/#consistent-naming) to follow
34 | when naming a gem.
35 |
36 | % tree
37 | .
38 | ├── hola.gemspec
39 | └── lib
40 | └── hola.rb
41 |
42 | Code for your package is placed within the `lib` directory. The convention is
43 | to have *one* Ruby file with the *same* name as your gem, since that gets
44 | loaded when `require 'hola'` is run. That one file is in charge of setting up
45 | your gem's code and API.
46 |
47 | The code inside of `lib/hola.rb` is pretty bare bones. It just makes sure that you
48 | can see some output from the gem:
49 |
50 | % cat lib/hola.rb
51 | class Hola
52 | def self.hi
53 | puts "Hello world!"
54 | end
55 | end
56 |
57 | The gemspec defines what’s in the gem, who made it, and the version of the gem.
58 | It’s also your interface to [RubyGems.org](http://rubygems.org). All of the
59 | information you see on a gem page
60 | (like [jekyll](http://rubygems.org/gems/jekyll)’s) comes from the gemspec.
61 |
62 | % cat hola.gemspec
63 | Gem::Specification.new do |s|
64 | s.name = 'hola'
65 | s.version = '0.0.0'
66 | s.date = '2010-04-28'
67 | s.summary = "Hola!"
68 | s.description = "A simple hello world gem"
69 | s.authors = ["Nick Quaranto"]
70 | s.email = 'nick@quaran.to'
71 | s.files = ["lib/hola.rb"]
72 | s.homepage =
73 | 'http://rubygems.org/gems/hola'
74 | s.license = 'MIT'
75 | end
76 |
77 | > The description member can be much longer than you see in this example. If it
78 | > matches `/^== [A-Z]/` then the description will be run through
79 | > [RDoc's markup formatter](https://github.com/rdoc/rdoc) for display on
80 | > the RubyGems web site. Be aware though that other consumers of the data might not
81 | > understand this markup.
82 |
83 | Look familiar? The gemspec is also Ruby, so you can wrap scripts to generate
84 | the file names and bump the version number. There are lots of fields the
85 | gemspec can contain. To see them all check out the full
86 | [reference](/specification-reference).
87 |
88 | After you have created a gemspec, you can build a gem from it. Then you can install
89 | the generated gem locally to test it out.
90 |
91 | % gem build hola.gemspec
92 | Successfully built RubyGem
93 | Name: hola
94 | Version: 0.0.0
95 | File: hola-0.0.0.gem
96 |
97 | % gem install ./hola-0.0.0.gem
98 | Successfully installed hola-0.0.0
99 | 1 gem installed
100 |
101 | Of course, the smoke test isn’t over yet: the final step is to `require` the gem and use it:
102 |
103 | % irb
104 | >> require 'hola'
105 | => true
106 | >> Hola.hi
107 | Hello world!
108 |
109 | > If you're using an earlier Ruby than 1.9.2, you need to start the
110 | > session with `irb -rubygems` or require the rubygems library after
111 | > you launch irb.
112 |
113 | Now you can share hola with the rest of the Ruby community. Publishing your
114 | gem out to RubyGems.org only takes one command, provided that you have an account on
115 | the site. To setup your computer with your RubyGems account:
116 |
117 | $ curl -u qrush https://rubygems.org/api/v1/api_key.yaml >
118 | ~/.gem/credentials; chmod 0600 ~/.gem/credentials
119 |
120 | Enter host password for user 'qrush':
121 |
122 | > If you're having problems with curl, OpenSSL, or certificates, you might want to
123 | > simply try entering the above URL in your browser's address bar. Your browser will
124 | > ask you to login to RubyGems.org. Enter your username and password. Your browser
125 | > will now try to download the file api_key.yaml. Save it in ~/.gem and call it 'credentials'
126 |
127 | Once this has been setup, you can push out the gem:
128 |
129 | % gem push hola-0.0.0.gem
130 | Pushing gem to RubyGems.org...
131 | Successfully registered gem: hola (0.0.0)
132 |
133 | In just a short time (usually less than a minute), your gem will be available for
134 | installation by anyone. You can see it [on the RubyGems.org site](https://rubygems.org/gems/hola)
135 | or grab it from any computer with RubyGems installed:
136 |
137 | % gem list -r hola
138 |
139 | *** REMOTE GEMS ***
140 |
141 | hola (0.0.0)
142 |
143 | % gem install hola
144 | Successfully installed hola-0.0.0
145 | 1 gem installed
146 |
147 | It’s really that easy to share code with Ruby and RubyGems.
148 |
149 | Requiring more files
150 | --------------------
151 |
152 | Having everything in one file doesn't scale well. Let's add some more code to
153 | this gem.
154 |
155 | % cat lib/hola.rb
156 | class Hola
157 | def self.hi(language = "english")
158 | translator = Translator.new(language)
159 | translator.hi
160 | end
161 | end
162 |
163 | class Hola::Translator
164 | def initialize(language)
165 | @language = language
166 | end
167 |
168 | def hi
169 | case @language
170 | when "spanish"
171 | "hola mundo"
172 | else
173 | "hello world"
174 | end
175 | end
176 | end
177 |
178 | This file is getting pretty crowded. Let's break out the `Translator` into a
179 | separate file. As mentioned before, the gem's root file is in charge of
180 | loading code for the gem. The other files for a gem are usually placed in a
181 | directory of the same name of the gem inside of `lib`. We can split this gem
182 | out like so:
183 |
184 | % tree
185 | .
186 | ├── hola.gemspec
187 | └── lib
188 | ├── hola
189 | │ └── translator.rb
190 | └── hola.rb
191 |
192 | The `Translator` is now in `lib/hola`, which can easily be picked up with a
193 | `require` statement from `lib/hola.rb`. The code for the `Translator` did not
194 | change much:
195 |
196 | % cat lib/hola/translator.rb
197 | class Translator
198 | def initialize(language)
199 | @language = language
200 | end
201 |
202 | def hi
203 | case @language
204 | when "spanish"
205 | "hola mundo"
206 | else
207 | "hello world"
208 | end
209 | end
210 | end
211 |
212 | But now the `hola.rb` file has some code to load the `Translator`:
213 |
214 | % cat lib/hola.rb
215 | class Hola
216 | def self.hi(language = "english")
217 | translator = Translator.new(language)
218 | translator.hi
219 | end
220 | end
221 |
222 | require 'hola/translator'
223 |
224 | > Gotcha:
225 | > For newly created folder/file, do not forget to add one entry in hola.gemspec file, as shown-
226 |
227 | % cat hola.gemspec
228 | Gem::Specification.new do |s|
229 | ...
230 | s.files = ["lib/hola.rb", "lib/hola/translator.rb"]
231 | ...
232 | end
233 |
234 | > without the above change, new folder would not be included into the installed gem.
235 |
236 | Let's try this out. First, fire up `irb`:
237 |
238 | % irb -Ilib -rhola
239 | irb(main):001:0> Hola.hi("english")
240 | => "hello world"
241 | irb(main):002:0> Hola.hi("spanish")
242 | => "hola mundo"
243 |
244 | We need to use a strange command line flag here: `-Ilib`. Usually RubyGems
245 | includes the `lib` directory for you, so end users don't need to worry about
246 | configuring their load paths. However, if you're running the code outside of
247 | RubyGems, you have to configure things yourself. It's possible to manipulate
248 | the `$LOAD_PATH` from within the code itself, but that's considered an
249 | anti-pattern in most cases. There are many more anti-patterns (and good patterns!)
250 | for gems, explained in [this guide](/patterns).
251 |
252 | If you've added more files to your gem, make sure to remember to add them to
253 | your gemspec's `files` array before publishing a new gem! For this reason (among others),
254 | many developers automate this with
255 | [Hoe](https://github.com/seattlerb/hoe),
256 | [Jeweler](https://github.com/technicalpickles/jeweler),
257 | [Rake](https://github.com/jimweirich/rake),
258 | [Bundler](http://railscasts.com/episodes/245-new-gem-with-bundler), or
259 | [just a dynamic gemspec
260 | ](https://github.com/wycats/newgem-template/blob/master/newgem.gemspec).
261 |
262 | Adding more directories with more code from here is pretty much the same
263 | process. Split your Ruby files up when it makes sense! Making a sane order for
264 | your project will help you and your future maintainers from headaches down the
265 | line.
266 |
267 | Adding an executable
268 | --------------------
269 |
270 | In addition to providing libraries of Ruby code, gems can also expose one or many
271 | executable files to your shell's `PATH`. Probably the best known example of
272 | this is `rake`. Another very useful one is `prettify_json.rb`, included
273 | with the [JSON](http://rubygems.org/gems/json) gem, which formats JSON in a
274 | readable manner (and is included with Ruby 1.9). Here's an example:
275 |
276 | % curl -s http://jsonip.com/ | \
277 | prettify_json.rb
278 | {
279 | "ip": "24.60.248.134"
280 | }
281 |
282 | Adding an executable to a gem is a simple process. You just need to place the file in
283 | your gem's `bin` directory, and then add it to the list of executables
284 | in the gemspec. Let's add one for the Hola gem. First create the file
285 | and make it executable:
286 |
287 | % mkdir bin
288 | % touch bin/hola
289 | % chmod a+x bin/hola
290 |
291 | The executable file itself just needs a
292 | [shebang](http://www.catb.org/jargon/html/S/shebang.html) in order to figure out
293 | what program to run it with. Here's what Hola's executable looks like:
294 |
295 | % cat bin/hola
296 | #!/usr/bin/env ruby
297 |
298 | require 'hola'
299 | puts Hola.hi(ARGV[0])
300 |
301 | All it's doing is loading up the gem, and passing the first command line
302 | argument as the language to say hello with. Here's an example of running it:
303 |
304 | % ruby -Ilib ./bin/hola
305 | hello world
306 |
307 | % ruby -Ilib ./bin/hola spanish
308 | hola mundo
309 |
310 | Finally, to get Hola's executable included when you push the gem, you'll need
311 | to add it in the gemspec.
312 |
313 | % head -4 hola.gemspec
314 | Gem::Specification.new do |s|
315 | s.name = 'hola'
316 | s.version = '0.0.1'
317 | s.executables << 'hola'
318 |
319 | Push up that new gem, and you'll have your own command line utility published!
320 | You can add more executables as well in the `bin` directory if you need to,
321 | there's an `executables` array field on the gemspec.
322 |
323 | > Note that you should change the gem's version when pushing up a new release.
324 | > For more information on gem versioning, see the [Patterns Guide](/patterns/#semantic-versioning)
325 |
326 | Writing tests
327 | --------------
328 |
329 | Testing your gem is extremely important. Not only does it help assure you that
330 | your code works, but it helps others know that your gem does its job. When
331 | evaluating a gem, Ruby developers tend to view a solid test suite (or lack thereof)
332 | as one of the main reasons for trusting that piece of code.
333 |
334 | Gems support adding test files into the package itself so tests can be run
335 | when a gem is downloaded. An entire community effort has sprung up called
336 | [GemTesters](http://test.rubygems.org/) to help document how gem test suites
337 | run on different architectures and interpreters of Ruby.
338 |
339 | In short: *TEST YOUR GEM!* Please!
340 |
341 | `Test::Unit` is Ruby's built-in test framework. There are
342 | [lots](http://www.mikeperham.com/2012/09/25/minitest-ruby-1-9s-test-framework/) of
343 | [tutorials](https://github.com/seattlerb/minitest/blob/master/README.txt) for
344 | using it online. There are many other test frameworks available for Ruby as
345 | well. [RSpec](http://rspec.info/) is a popular choice. At the end of the day,
346 | it doesn't matter what you use, just *TEST*!
347 |
348 | Let's add some tests to Hola. This requires adding a few more files, namely a
349 | `Rakefile` and a brand new `test` directory:
350 |
351 | % tree
352 | .
353 | ├── Rakefile
354 | ├── bin
355 | │ └── hola
356 | ├── hola.gemspec
357 | ├── lib
358 | │ ├── hola
359 | │ │ └── translator.rb
360 | │ └── hola.rb
361 | └── test
362 | └── test_hola.rb
363 |
364 | The `Rakefile` gives you some simple automation for running tests:
365 |
366 | % cat Rakefile
367 | require 'rake/testtask'
368 |
369 | Rake::TestTask.new do |t|
370 | t.libs << 'test'
371 | end
372 |
373 | desc "Run tests"
374 | task :default => :test
375 |
376 | Now you can run `rake test` or simply just `rake` to run tests. Woot! Here's
377 | a basic test file for hola:
378 |
379 | % cat test/test_hola.rb
380 | require 'minitest/autorun'
381 | require 'hola'
382 |
383 | class HolaTest < Minitest::Test
384 | def test_english_hello
385 | assert_equal "hello world",
386 | Hola.hi("english")
387 | end
388 |
389 | def test_any_hello
390 | assert_equal "hello world",
391 | Hola.hi("ruby")
392 | end
393 |
394 | def test_spanish_hello
395 | assert_equal "hola mundo",
396 | Hola.hi("spanish")
397 | end
398 | end
399 |
400 | Finally, to run the tests:
401 |
402 | % rake test
403 | (in /Users/qrush/Dev/ruby/hola)
404 | Loaded suite
405 | Started
406 | ...
407 | Finished in 0.000736 seconds.
408 |
409 | 3 tests, 3 assertions, 0 failures, 0 errors, 0 skips
410 |
411 | Test run options: --seed 15331
412 |
413 | It's green! Well, depending on your shell colors. For more great examples, the best thing you can do is hunt around
414 | [GitHub](https://github.com/search?utf8=%E2%9C%93&q=stars%3A%3E100+forks%3A%3E10&type=Repositories&ref=advsearch&l=Ruby) and read some code.
415 |
416 | Documenting your code
417 | ---------------------
418 |
419 | By default most gems use RDoc to generate docs. There are plenty of
420 | [great tutorials](http://docs.seattlerb.org/rdoc/RDoc/Markup.html) for learning how
421 | to mark up your code with RDoc. Here's a simple example:
422 |
423 | # The main Hola driver
424 | class Hola
425 | # Say hi to the world!
426 | #
427 | # Example:
428 | # >> Hola.hi("spanish")
429 | # => hola mundo
430 | #
431 | # Arguments:
432 | # language: (String)
433 |
434 | def self.hi(language = "english")
435 | translator = Translator.new(language)
436 | puts translator.hi
437 | end
438 | end
439 |
440 | Another great option for documentation is [YARD](http://yardoc.org/), since
441 | when you push a gem, [RubyDoc.info](http://rubydoc.info/) generates YARDocs
442 | automatically from your gem. YARD is backwards compatible with RDoc, and it
443 | has a [good
444 | introduction](http://rubydoc.info/docs/yard/file/docs/GettingStarted.md) on
445 | what's different and how to use it.
446 |
447 | Wrapup
448 | ------
449 |
450 | With this basic understanding of building your own RubyGem, we hope you'll be
451 | on your way to making your own! The next few guides cover patterns in making a
452 | gem and the other capabilities of the RubyGems system.
453 |
454 | Credits
455 | -------
456 |
457 | This tutorial was adapted from [Gem Sawyer, Modern Day Ruby
458 | Warrior](http://rubylearning.com/blog/2010/10/06/gem-sawyer-modern-day-ruby-warrior/).
459 | The code for this gem can be found [on GitHub](https://github.com/qrush/hola).
460 |
--------------------------------------------------------------------------------