• Stars
    star
    332
  • Rank 126,941 (Top 3 %)
  • Language
    Ruby
  • License
    MIT License
  • Created almost 8 years ago
  • Updated 3 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

This gem implements a flexible time-ordered activity feeds commonly used within social networking applications. As events occur, they are pushed into the Feed and distributed to all users that need to see the event. Upon the user visiting their "feed page", a pre-populated ordered list of events is returned by the library.

SimpleFeed


Donate using Liberapay   https://img.shields.io/liberapay/goal/kigster

1. Scalable, Easy to Use Activity Feed Implementation.

Note
please feel free to read this README in the formatted-for-print PDF Version.

1.1. Build & Gem Status

MIT licensed RSpec Rubocop

Gem Version Inline docs Coverage

1.2. Test Coverage Map

Coverage Map

Important
Please read the (somewhat outdated) blog post Feeding Frenzy with SimpleFeed launching this library. Please leave comments or questions in the discussion thread at the bottom of that post. Thanks!

If you like to see this project grow, your donation of any amount is much appreciated.

Donate

This is a fast, pure-ruby implementation of an activity feed concept commonly used in social networking applications. The implementation is optimized for read-time performance and high concurrency (lots of users), and can be extended with custom backend providers. One data provider come bundled: the production-ready Redis provider.

Important Notes and Acknowledgements:

  • SimpleFeed does not depend on Ruby on Rails and is a pure-ruby implementation

  • SimpleFeed requires MRI Ruby 2.3 or later

  • SimpleFeed is currently live in production

  • SimpleFeed is open source thanks to the generosity of Simbi, Inc.

2. Features

SimpleFeed is a Ruby Library that can be plugged into any application to power a fast, Redis-based activity feed implementation so common on social networking sites. SimpleFeed offers the following features:

  • Modelled after graph-relationships similar to those on Twitter (bi-directional independent follow relationships):

    • Feed maintains a reverse-chronological order for heterogeneous events for each user.

    • It offers a constant time lookup for user’s feed, avoiding complex SQL joins to render it.

    • An API to read/paginate the feed for a given user

    • As well as to query the total unread items in the feed since it was last read by the user (typically shown on App icons).

  • Scalable and well performing Redis-based activity feed —

    • Scales to millions of users (will need to use Twemproxy to shard across several Redis instances)

    • Stores a fixed number of events for each unique "user" — the default is 1000. When the feed reaches 1001 events, the oldest event is offloaded from the activity.

  • Implementation properties:

    • Fully thread-safe implementation, writing events can be done in eg. Sidekiq.

    • Zero assumptions about what you are storing: the "data" is just a string. Serialize it with JSON, Marshall, YAML, or whatever.

    • You can create as many different types of feeds per application as you like (no Ruby Singletons used).

    • Customize mapping from user_id to the activity id based on your business logic (more on this later).

2.1. Publishing Events

Pushing events to the feed requires the following:

  • An Event consisting of:

    • String data that, most commonly, is a foreign key to a database table, but can really be anything you like.

    • Float at (typically, the timestamp, but can be any float number)

  • One or more user IDs, or event consumers: basically — who should see the event being published in their feed.

You publish an event by choosing a set of users whose feed should be updated. For example, were you re-implementing Twitter, your array of user_ids when publishing an event would be all followers of the Tweet’s author. While the data would probably be the Tweet ID.

Note
Publishing an event to the feeds of N users is roughly a O(N * log(N)) operation

2.2. Consuming Events (Reading / Rendering the Feed)

You can fetch the chronologically ordered events for a particular user, using:

  • Methods on the activity such as paginate, fetch.

    • Reading feed for one user (or one type of user) is a O(1) operation

  • For each activity (user) you can fetch the total_count and the unread_count — the number of total and new items in the feed, where unread_count is computed since the user last reset their read status.

    • Note: total_count can never exceed the maximum size of the feed that you configured. The default is 1000 items.

    • The last_read timestamp can be automatically reset when the user is shown the feed via paginate method (whether or not its reset is controlled via a method argument).

2.3. Modifying User’s Feed

For any given user, you can:

  • Wipe their feed with wipe

  • Selectively remove items from the feed with delete_if.

    • For instance, if a user un-follows someone they shouldn’t see their events anymore, so you’d have to call delete_if and remove any events published by the unfollowed user.

2.4. Aggregating Events

This is a feature planned for future versions.

Help us much appreciated, even if you are not a developer, but have a clear idea about how it should work.

3. Commercial & Enterprise Support

Commercial Support plans are available for SimpleFeed through author’s ReinventONE Inc consulting company. Please reach out to kig AT reinvent.one for more information.

4. Usage

4.1. Example

Please read the additional documentation, including the examples, on the project’s Github Wiki.

Below is a screen shot of an actual activity feed powered by this library.

usage

4.2. Providers

A key concept to understanding SimpleFeed gem, is that of a provider, which is effectively a persistence implementation for the events belonging to each user.

One providers are supplied with this gem: the production-ready :redis provider, which uses the sorted set Redis data type to store and fetch the events, scored by time (but not necessarily).

You initialize a provider by using the SimpleFeed.provider([Symbol]) method.

4.3. Configuration

Below we configure a feed called :newsfeed, which in this example will be populated with the various events coming from the followers.

require 'simplefeed'

# Let's define a Redis-based feed, and wrap Redis in a in a ConnectionPool.

SimpleFeed.define(:newsfeed) do |f|
  f.provider   = SimpleFeed.provider(:redis,
                                      redis: -> { ::Redis.new },
                                      pool_size: 10)
  f.per_page   = 50     # default page size
  f.batch_size = 10     # default batch size
  f.namespace  = 'nf'   # only needed if you use the same redis for more than one feed
end

After the feed is defined, the gem creates a similarly named method under the SimpleFeed namespace to access the feed. For example, given a name such as :newsfeed the following are all valid ways of accessing the feed:

  • SimpleFeed.newsfeed

  • SimpleFeed.get(:newsfeed)

You can also get a full list of currently defined feeds with SimpleFeed.feed_names method.

4.4. Reading from and writing to the feed

For the impatient, here is a quick way to get started with the SimpleFeed.

# Let's use the feed we defined earlier and create activity for all followers of the current user
publish_activity = SimpleFeed.newsfeed.activity(@current_user.followers.map(&:id))

# Store directly the value and the optional time stamp
publish_activity.store(value: 'hello', at: Time.now)
# => true  # indicates that value 'hello' was not yet in the feed (all events must be unique)

# Or, using the event form:
publish_activity.store(event: SimpleFeed::Event.new('good bye', Time.now))
# => true

As we’ve added the two events for these users, we can now read them back, sorted by the time and paginated:

# Let's grab the first follower
user_activity = SimpleFeed.newsfeed.activity(@current_user.followers.first.id)

# Now we can paginate the events, while resetting this user's last-read timestamp:
user_activity.paginate(page: 1, reset_last_read: true)
# [
#     [0] #<SimpleFeed::Event: value=hello, at=1480475294.0579991>,
#     [1] #<SimpleFeed::Event: value=good bye, at=1480472342.8979871>,
# ]
Important
Note that we stored the activity by passing an array of users, but read the activity for just one user. This is how you’d use SimpleFeed most of the time, with the exception of the alternative mapping described below.

4.5. User IDs

In the previous section you saw the examples of publishing events to many feeds, and then reading the activity for a given user.

SimpleFeed supports user IDs that are either numeric (integer) or string-based (eg, UUID). Numeric IDs are best for simplest cases, and are the most compact. String keys offer the most flexibility.

4.5.1. Activity Keys

In the next section we’ll talk about generating keys from user_ids. We mean — Redis Hash keys that uniquely map a user (or a set of users) to the activity feed they should see.

There are up to two keys that are computed depending on the situation:

  • data_key is used to store the actual feed events

  • meta_key is used to store user’s last_read status

4.5.2. Partitioning Schema

Note
This feature is only available in SimpleFeed Version 3+.

You can take advantage of string user IDs for situations where your feed requires keys to be composite for instance. Just remember that SimpleFeed does not care about what’s in your user ID, and even what you call "a user". It’s convenient to think of the activities in terms of users, because typically each user has a unique feed that only they see.

But you can just as easily use zip code as the unique activity ID, and create one feed of events per geographical location, that all folks living in that zip code share. But what about other countries?

Now you use partitioning scheme: make the "user_id" argument a combination iso_country_code.postal_code, eg for San Francisco, you’d use us.94107, but for Australia you could use, eg au.3148.

4.5.3. Relationship between an Activity and a User

One to One

In the most common case, you will have one activity per user.

For instance, in the Twitter example, each Twitter user has a unique tweeter feed that only they see.

The events are published when someone posts a tweet, to the array of all users that follow the Tweet author.

One to Many

However, SimpleFeed supports one additional use-case, where you might have one activity shared among many users.

Imagine a service that notifies residents of important announcements based on user’s zip code of residence.

We want this feed to work as follows:

  • All users that share a zip-code should see the same exact feed.

  • However, all users should never share the individual’s last_read status: so if two people read the same activity from the same zip code, their unread_count should change independently.

In terms of the activity keys, this means:

  • data_key should be based on the zip-code of each user, and be one to many with users.

  • meta_key should be based on the user ID as we want it to be 1-1 with users.

To support this use-case, SimpleFeed supports two optional transformer lambdas that can be applied to each user object when computing their activity feed hash key:

SimpleFeed.define(:zipcode_alerts) do |f|
  f.provider   = SimpleFeed.provider(:redis, redis: -> { ::Redis.new }, pool_size: 10)
  f.namespace  = 'zc'
  f.data_key_transformer = ->(user) { user.zip_code }  # actual feed data is stored once per zip code
  f.meta_key_transformer = ->(user) { user.id }        # last_read status is stored once per user
end

When you publish events into this feed, you would need to provide User objects that all respond to .zip_code method (based on the above configuration). Since the data is only defined by Zip Code, you probably don’t want to be publishing it via a giant array of users. Most likely, you’ll want to publish event based on the zip code, and consume them based on the user ID.

To support this user-case, let’s modify our transformer lambda (only the data one) as follows — so that it can support both the consuming read by a user case, and the publishing a feed by zip code case:

Alternatively, you could do something like this:

  f.data_key_transformer = ->(entity) do
    case entity
      when User
        entity.zip_code.to_i
      when String # UUIDs
        User.find(entity)&.zip_code.to_i
      when ZipCode, Numeric
        entity.to_i
      else
        raise ArgumentError, "Invalid type #{entity.class.name}"
    end
  end

Just make sure that your users always have .zip_code defined, and that ZipCode.new(94107).to_i returns exactly the same thing as @user.zip_code.to_i or your users won’t see the feeds they are supposed to see.

4.6. The Two Forms of the Feed API

The feed API is offered in two forms:

  1. single-user form, and

  2. a batch (multi-user) form.

The method names and signatures are the same. The only difference is in what the methods return:

  1. In the single user case, the return of, say, #total_count is an Integer value representing the total count for this user.

  2. In the multi-user case, the return is a SimpleFeed::Response instance, that can be thought of as a Hash, that has the user IDs as the keys, and return results for each user as a value.

Please see further below the details about the Batch API.

Single-User API

In the examples below we show responses based on a single-user usage. As previously mentioned, the multi-user usage is the same, except what the response values are, and is discussed further down below.

Let’s take a look at a ruby session, which demonstrates return values of the feed operations for a single user:

require 'simplefeed'

# Define the feed using Redis provider, which uses
# SortedSet to keep user's events sorted.
SimpleFeed.define(:followers) do |f|
  f.provider = SimpleFeed.provider(:redis)
  f.per_page = 50
  f.per_page = 2
end

# Let's get the Activity instance that wraps this
activity = SimpleFeed.followers.activity(user_id)         # => [... complex object removed for brevity ]

# let's clear out this feed to ensure it's empty
activity.wipe                                             # => true

# Let's verify that the counts for this feed are at zero
activity.total_count                                      # => 0
activity.unread_count                                     # => 0

# Store some events
activity.store(value: 'hello')                            # => true
activity.store(value: 'goodbye', at: Time.now - 20)       # => true
activity.unread_count                                     # => 2

# Now we can paginate the events, while resetting this user's last-read timestamp:
activity.paginate(page: 1, reset_last_read: true)
# [
#     [0] #<SimpleFeed::Event: value=good bye, at=1480475294.0579991>,
#     [1] #<SimpleFeed::Event: value=hello, at=1480475294.057138>
# ]
# Now the unread_count should return 0 since the user just "viewed" the feed.
activity.unread_count                                     # => 0
activity.delete(value: 'hello')                           # => true
# the next method yields to a passed in block for each event in the user's feed, and deletes
# all events for which the block returns true. The return of this call is the
# array of all events that have been deleted for this user.
activity.delete_if do |event, user_id|
  event.value =~ /good/
end
# => [
#     [0] #<SimpleFeed::Event: value=good bye, at=1480475294.0579991>
# ]
activity.total_count                                      # => 0

You can fetch all items (optionally filtered by time) in the feed using #fetch, #paginate and reset the last_read timestamp by passing the reset_last_read: true as a parameter.

Batch (Multi-User) API

This API should be used when dealing with an array of users (or, in the future, a Proc or an ActiveRecord relation).

There are several reasons why this API should be preferred for operations that perform a similar action across a range of users: various provider implementations can be heavily optimized for concurrency, and performance.

The Redis Provider, for example, uses a notion of pipelining to send updates for different users asynchronously and concurrently.

Multi-user operations return a SimpleFeed::Response object, which can be used as a hash (keyed on user_id) to fetch the result of a given user.

# Using the Feed API with, eg #find_in_batches
@event_producer.followers.find_in_batches do |group|

  # Convert a group to the array of IDs and get ready to store
  activity = SimpleFeed.get(:followers).activity(group.map(&:id))
  activity.store(value: "#{@event_producer.name} liked an article")

  # => [Response] { user_id1 => [Boolean], user_id2 => [Boolean]... }
  # true if the value was stored, false if it wasn't.
end
Activity Feed DSL (Domain-Specific Language)

The library offers a convenient DSL for adding feed functionality into your current scope.

To use the module, just include SimpleFeed::DSL where needed, which exports just one primary method #with_activity. You call this method and pass an activity object created for a set of users (or a single user), like so:

require 'simplefeed/dsl'
include SimpleFeed::DSL

feed = SimpleFeed.newsfeed
activity = feed.activity(current_user.id)
data_to_store = %w(France Germany England)

def report(value)
  puts value
end

with_activity(activity, countries: data_to_store) do
  # we can use countries as a variable because it was passed above in **opts
  countries.each do |country|
    # we can call #store without a receiver because the block is passed to
    # instance_eval
    store(value: country) { |result| report(result ? 'success' : 'failure') }
    # we can call #report inside the proc because it is evaluated in the
    # outside context of the #with_activity

    # now let's print a color ASCII dump of the entire feed for this user:
    color_dump
  end
  printf "Activity counts are: %d unread of %d total\n", unread_count, total_count
end

The DSL context has access to two additional methods:

  • #event(value, at) returns a fully constructed SimpleFeed::Event instance

  • #color_dump prints to STDOUT the ASCII text dump of the current user’s activities (events), as well as the counts and the last_read shown visually on the time line.

#color_dump

Below is an example output of color_dump method, which is intended for the debugging purposes.

sf color dump
Figure 1. #color_dump method output

5. Complete API

For completeness sake we’ll show the multi-user API responses only. For a single-user use-case the response is typically a scalar, and the input is a singular user_id, not an array of ids.

Multi-User (Batch) API

Each API call at this level expects an array of user IDs, therefore the return value is an object, SimpleFeed::Response, containing individual responses for each user, accessible via response[user_id] method.

@multi = SimpleFeed.get(:feed_name).activity(User.active.map(&:id))

@multi.store(value:, at:)
@multi.store(event:)
# => [Response] { user_id => [Boolean], ... } true if the value was stored, false if it wasn't.

@multi.delete(value:, at:)
@multi.delete(event:)
# => [Response] { user_id => [Boolean], ... } true if the value was removed, false if it didn't exist

@multi.delete_if do |event, user_id|
  # if the block returns true, the event is deleted and returned
end
# => [Response] { user_id => [deleted_event1, deleted_event2, ...], ... }

# Wipe the feed for a given user(s)
@multi.wipe
# => [Response] { user_id => [Boolean], ... } true if user activity was found and deleted, false otherwise

# Return a paginated list of all items, optionally with the total count of items
@multi.paginate(page: 1,
                per_page: @multi.feed.per_page,
                with_total: false,
                reset_last_read: false)
# => [Response] { user_id => [Array]<Event>, ... }
# Options:
#   reset_last_read: false — reset last read to Time.now (true), or the provided timestamp
#   with_total: true — returns a hash for each user_id:
#        => [Response] { user_id => { events: Array<Event>, total_count: 3 }, ... }

# Return un-paginated list of all items, optionally filtered
@multi.fetch(since: nil, reset_last_read: false)
# => [Response] { user_id => [Array]<Event>, ... }
# Options:
#   reset_last_read: false — reset last read to Time.now (true), or the provided timestamp
#   since: <timestamp> — if provided, returns all items posted since then
#   since: :last_read — if provided, returns all unread items and resets +last_read+

@multi.reset_last_read
# => [Response] { user_id => [Time] last_read, ... }

@multi.total_count
# => [Response] { user_id => [Integer, String] total_count, ... }

@multi.unread_count
# => [Response] { user_id => [Integer, String] unread_count, ... }

@multi.last_read
# => [Response] { user_id => [Time] last_read, ... }

6. Providers

As we’ve discussed above, a provider is an underlying persistence mechanism implementation.

It is the intention of this gem that:

  • it should be easy to write new providers

  • it should be easy to swap out providers

One provider is included with this gem:

6.1. SimpleFeed::Providers::Redis::Provider

Redis Provider is a production-ready persistence adapter that uses the sorted set Redis data type.

This provider is optimized for large writes and can use either a single Redis instance for all users of your application, or any number of Redis shards by using a Twemproxy in front of the Redis shards.

If you set environment variable REDIS_DEBUG to true and run the example (see below) you will see every operation redis performs. This could be useful in debugging an issue or submitting a bug report.

7. Running the Examples and Specs

Source code for the gem contains the examples folder with an example file that can be used to test out the providers, and see what they do under the hood.

Both the specs and the example requires a local redis instance to be available.

To run it, checkout the source of the library, and then:

git clone https://github.com/kigster/simple-feed.git
cd simple-feed

# on OSX with HomeBrew:
brew install redis
brew services start redis

# check that your redis is up:
redis-cli info

# install bundler and other dependencies
gem install bundler --version 2.1.4
bundle install
bundle exec rspec  # make sure tests are passing

# run the example:
ruby examples/redis_provider_example.rb

The above command will help you download, setup all dependencies, and run the examples for a single user:

running example
Figure 2. Running Redis Example in a Terminal

If you set REDIS_DEBUG variable prior to running the example, you will be able to see every single Redis command executed as the example works its way through. Below is a sample output:

running example redis debug
Figure 3. Running Redis Example with REDIS_DEBUG set

7.1. Generating Ruby API Documentation

rake doc

This should use Yard to generate the documentation, and open your browser once it’s finished.

7.2. Installation

Add this line to your application’s Gemfile:

gem 'simple-feed'

And then execute:

$ bundle

Or install it yourself as:

$ gem install simple-feed

7.3. Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

7.4. Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/kigster/simple-feed

7.5. License

The gem is available as open source under the terms of the MIT License.

FOSSA Scan Status

7.6. Acknowledgements

  • This project is conceived and sponsored by Simbi, Inc..

  • Author’s personal experience at Wanelo, Inc. has served as an inspiration.

More Repositories

1

cmake-project-template

This project is aimed at jump-starting a C/C++ project that can build libraries, binaries and have a working unit test suite. It uses CMake build system and is deliberately completely minimal.
C++
881
star
2

sym

Sym is a command line utility and a Ruby API that makes it trivial to encrypt and decrypt sensitive data. Unlike many other existing encryption tools, sym focuses on usability and streamlined interface (CLI), with the goal of making encryption easy and transparent. The result? There is no excuse for keeping your application secrets unencrypted :)
Ruby
136
star
3

bashmatic

Optimized for humans, 500+ BASH functions for all walks of life. Über Toölkit for über geeks and UNIX command line power users.
Shell
133
star
4

laser-cutter

Similar to boxmaker, this ruby gem generates PDFs that can be used as a basis for cutting boxes on a typical laser cutter. The intention is to create an extensible, well tested, and modern ruby framework for generating PDF templates used in laser cutting.
Ruby
91
star
5

ventable

Event/Observable support for plain ruby with options for grouping observers and wrapping notifications in blocks of code, such as transaction handling.
Ruby
58
star
6

warp-dir

Warp Directory – a drop-in replacement (superset to be precise) of the nifty 'wd' ZSH module. This one is written in ruby, and works with any shell.
Ruby
40
star
7

puma-daemon

Puma (starting version 5) removed automatic demonization from the gem itself. This functionality was extracted to this gem, which supports Puma v5 and v6.
Ruby
37
star
8

arli

Arli is the command line tool, that's both — the Arduino Library manager that's decoupled from any IDE, as well a project generator based on "arduino-cmake". By coupling dependency management with CMake-based build system, Arli provides an easy way to package, share, and distribute complex Arduino projects.
Ruby
28
star
9

pullulant

Kick start a fresh development environment on any Mac with OS-X El Capitan, with this opinionated, but modular and customizable installer. It's based on HomeBrew, SproutWrap cookbooks, and about 2K lines of Bash programming :)
Shell
12
star
10

dupervisor

This library converts config files between – YAML, JSON and Windows INI file format. For example, supervisord uses INI file format. Using the gem you can configure supervisord via a YAML file, and generate INI as needed. DuperVisor installs `dv` CLI converter. Run `dv -h` for help.
Ruby
9
star
11

librgb

C/C++ Library for RGB color manipulation and effects. The intention is to make it possible to use the library for Arduino-based projects. Current status: pre-Alpha.
C++
8
star
12

kigomoku-ios

Simple Gomoku (Five In A Row) game for iPhone
Objective-C
6
star
13

delicious-library-3-cloud-sync

A simple shell script so that the data files used by Delicious Library 3â„¢ software for Mac made by Delicious Monster Software can be shared across multiple computers in your possession.
Shell
6
star
14

attr_memoized

Memoize attributes in a thread-safe way. This ruby gem adds a `#attr_memoized` class method, that provides a lazy-loading mechanism for initializing "heavy" attributes, but in a thread-safe way. Instances thus created can be shared among threads.
Ruby
6
star
15

joyent-cloud-pricing

A collection of tools to help figure out Joyent cloud costs for an infrastructure of any size. Supports commit pricing discounts.
Ruby
5
star
16

sidekiq-cluster

Sidekiq cluster is a simple CLI wrapper around Sidekiq that allows running multiple Sidekiq processes as a single pool of workers.
Ruby
5
star
17

RotaryEncoderWithButton

Easily read rotary encoder buttons that also incorporate a push button, like Adafruit Rotary Encoder.
C++
5
star
18

search-emlx-mailbox

Rails 5.2-based application that uses Sunspot/Solr to index and import large number of emails either as individual files in "*.elmx" format, or by using an exported "mbox" format. Once imported, the app provides a simple and convenient search interface for finding all emails matching a given search string. Useful in depositions, legal proceedings, or just personal projects.
Ruby
4
star
19

dnsmadeeasy

A full-featured API client for managing DNS records hosted by DnsMadeEasy.com via their REST SDK v2. A powerful CLI command "dme" is installed for those script-centric. Ruby SDK is provided for those needing the integrate at deeper level.
Ruby
4
star
20

auto-dimming-clock

Digital wall clock, or a bed-side clock, or whatever type of clock you like, equipped with a rotary encoder knob, a photo resistor able to aid in adjusting brightness as it changes throughout the day. The clock can be equipped with an optional strip of neo pixels – for some extra color. Works with Arduino Uno, Nano, Mini Pro, as well as Teensy.
C++
4
star
21

molder

Molder is a command line tool for generating and running (in parallel) a set of related but similar commands. A key use-case is auto-generation of the host provisioning commands for an arbitrary cloud environment. The gem is not constrained to any particular cloud tool or even a command, and can be used to generate a consistent set of commands based on several customizable dimensions.
Ruby
4
star
22

pause

Fast, flexible, and easy to use rate limiter or throttler for multi-process ruby applications backed by Redis.
Ruby
3
star
23

helpful-tools

Personal collection of scripts, snippets, and more, typically written in ruby.
Ruby
3
star
24

makeabox

MakeABox – use this app with a laser cutter to create a box with notches that connect all sides together.
HTML
3
star
25

githuh

Github API command line client for fetching repos, looking up users, etc.
Ruby
3
star
26

kigame-cpp

A set of generic C++ interfaces and classes to aid with modeling basic 2-player board games.
C++
3
star
27

turnstile-rb

Turnstile is a ruby gem for tracking in near-real time concurrent live users on the site without introducing additional latency into the request.
Ruby
3
star
28

arduino-library

This gem encapsulates many concepts related to how Arduino Libraries are indexed, how their metadata is validated, or .properties file generated. It supports searching the Arduino library database for any terms. This gem is used by Arli — Arduino Installer CLI toolkit.
Ruby
3
star
29

kigaboom

Teensy + Audio Shield + TFT+ Infrared / Rotary Knobs = fully customizable audio digital signal processing station, with spectrum analyzer, peak meter, EQ and many more functions available via simple controls.
C++
3
star
30

cookbook-set-hostname

Why is not part of Chef? I have no idea. But here is how you can set your hostname correctly, and with FQDN. The hostname is set based on the specified domain name. Supports SmartOS, Ubuntu and CentOS.
Ruby
3
star
31

beatify

A wrapper project around "beet" open source music organizer, suitable for DJs with large music folders.
Shell
3
star
32

game-simon-says

C/C++ core of this simple pattern repeating game.
C++
2
star
33

cookbook-logrotate-s3

Rotate logs to S3 using logrotate and s3cmd
Ruby
2
star
34

register

Registry pattern for wrapping application globals in a module-level auto-generated accessors
Ruby
2
star
35

cookbook-pgbouncer-service

Installs pgBouncer from either sources or packages, configures the connections, and sets up a service.
Ruby
2
star
36

obstacle-avoiding-robot

Arduino-based project that drives on 4 DC motors and avoids things in front.
CMake
2
star
37

mms-mime

Ruby parser for MM7-wrapped MMS/MIME messages
Ruby
2
star
38

host_status

Generic facade that aggregates metrics for a given host running a particular application using pluggable methods including third-party APIs.
Ruby
2
star
39

saves-cli

Saves Service CLI Client for a proprietary horizontally sharded storage of product saves.
Ruby
2
star
40

flix-capacitor

A little flux/flix capacitor box based on Teensy 3.1 for showing pictures, clock, playing DJ sets, and starting a small rave in a recovery room.
Arduino
2
star
41

performance-compare

A simple gem that can be used to compare algorithm implementations in Ruby using a single thread, a thread pool, or a process pool.
Ruby
2
star
42

weather-pod

4-line LCD Screen shows temperature, humidity, barometric pressure and time. Project build using arduino-cmake, dependencies maintained by Arli.
CMake
2
star
43

cookbook-auto-updater

This Cookbook performs several operations on a newly provisioned Ubuntu machines to prepare them for server-side operation. It includes setting the timezone, and performing smart unattended update of all system packages and kernels, possibly requiring reboot.
Ruby
2
star
44

back-seat-driver

Autonomous Arduino Robot control library in C++. Easily drive various kinds of robots without blocking or sleeping. Supports servo-based bots and DC motor based using Adafruit Motor Shield.
C++
2
star
45

rules_ruby_lambda

Bazel rules for packaging and uploading AWS Lambdas
1
star
46

treename

Rename all files in multi-level folder tree based on custom logic, with optional custom callbacks. Use it to process batches of files to convert them eg. from WAV to MP3 or vice versa, while renaming them along the way.
Ruby
1
star
47

cookbook-dnsmadeeasy

DNS record management cookbook for automatically registering nodes with DnsMadeEasy provider.
Ruby
1
star
48

number-counting

Ruby Network Server to support NodeJS CLI and AI Clients
Ruby
1
star
49

sprout-pyenv

Sprout-wrap compatible cookbook to install pyenv using Brew, and then any version of Python using soloist.
Ruby
1
star
50

uri-io

Provides IO semantics for various URI schemes
Ruby
1
star
51

ruby-exercises

Ruby implementations of exercises I came across and thought they were fun.
Ruby
1
star
52

playgine

Gaming backend engine written in Rails 6, TypeScript, PostgreSQL
1
star
53

arduino-workspace

Shell
1
star
54

cmake-ccspec-template

CMake C++ project template that uses ccspec for unit testing, instead of Google Test library.
C++
1
star
55

wallclock-arduino

CMake-based project for a fancy digital Wall Clock with Neo Pixels, temperature, and other goodies.
CMake
1
star
56

makeabox.app

Work in progress — evolution of the original MakeABox application, this one will use Angular and Rails 6
Ruby
1
star
57

vscode-insider-settings

A set of simple makefile commands to export/import/swap settings for VSCode and VSCode Insiders
Makefile
1
star
58

AsciiDuino

Library that makes displaying shapes/frames on RainbowDuino LED Matrix easy using ASCII pictures as source input
C++
1
star
59

bazel-in-pictures

Various UML-like diagrams explaining Bazel API for those creating new rules
1
star
60

arli-cmake

Some additional helpers for arduino-cmake project, as well as the helpers to connect Arli library Manager.
CMake
1
star
61

cloud-kitchens-dispatch

Simulation of Order fulfillment in a Restaurant Kitchen
Ruby
1
star
62

boxbot

[WIP] Boxbot is a from the ground-up rewrite of the laser-cutter gem with some additional features planned. It generates templates meant to be used by a laser cutter to cut out a 3D box with matching tabs that allow the box to be "snapped into place" without screws, although screws can also be added.
Ruby
1
star
63

readonly

This gem offers a proxy class that can be used to create a read-only wrappers around any other class, by declaring which methods can be delegated to the wrapped class.
Ruby
1
star
64

kiguino

Collection of Arduino libraries and wrappers, written and used in various live projects. Most of the libraries hide some complexity and encapsulate a consistent approach to the *thing*, be that measuring a sensor, working with a rotary knob, etc.
C++
1
star
65

drb-cache

DRb::Cache is a ruby gem that offers a shared multi-process cache by transparently managing a DRb server process on the background.
Ruby
1
star
66

pythagoras

Super simple C++ calculator that computes either a hypothenuse from the equal cathet, or vice versa.
C++
1
star
67

timed-messages

Schedule defined as starting times and durations, good for integrating into embedded LED systems that are supposed to show a given artist at a given time. Arduino-free library with automated tests based on ccspec (C++17 required)
C++
1
star
68

solr-sunspot-cookbook

Fully automated installation, configuration and service definition for Solr Search engine with support for single master many replicas, and specifically configured to work with Sunspot Ruby Gem.
HTML
1
star
69

sparkfun7SD

Set of libraries for using Sparkfun seven-segment displays (4 digit), while using different means of communications, implemented as sub-libraries. Based on tutorials @ https://learn.sparkfun.com/tutorials/using-the-serial-7-segment-display
C++
1
star
70

require_dir

Easily and non-intrusively require files from sub-folders in ruby. Unlike require_all, this gem is meant to be included and does not break or affect load path.
Ruby
1
star
71

ventable-statsd

Integrate your Ventable events with Statsd in order to track some or all of the events that occur using a fast light-weight UDP protocol.
Ruby
1
star
72

sym-crypt

This library provides a simple interface allowing access to the symmetric encryption functionality provided by the OpenSSL library. It supports private key generation, encryption/decryption with the key, as well as encryption/decryption with an arbitrary user-defined password.
Ruby
1
star
73

super_uri

Extension to the OpenURI module that understands many additional types of URI resources, and is able to open and read them. Included are: file://, env://, osxkeychain://, redis://, memcached:// schemes.
Ruby
1
star