Get name of a function
Get function name with strictness and correctness in mind. Also works for arrow functions and getting correct name of bounded functions. Powered by [fn-name][].
get function name from stacktrace for node
Get the name of the function.
[](https://travis-ci.org/stefanpenner/get-caller-file) [](https://ci.a
get function name from stacktrace for web
Determine the `package.json#type` which applies to a location
random bytes from browserify stand alone
Returns an array of all enumerable symbol properties found directly upon a given object
Get callsites from the V8 stack trace API
random fill from browserify stand alone
Get the name of a named function
A cross browser microtask library
Set a function's name property
Helper function to get function arity
Get the command from a shebang
Apply ES2015 function.name semantics to all functions
Helper function to get function arity
create hashes for browserify
Utility for getting a function's name for node and the browser
Access memory using small fixed sized buffers
Caseless object set/get/has, very useful when working with HTTP headers.
Helper function to change the property 'name' of every function
get a list of identifiers that are initialised by a JavaScript AST node.
Extracted from Merb, get_args allows you to query a method for its argument names and defaults. This gem exists so you can get this functionality without having to include all of Merb.
This gem is a Pokemon wrapper for engineers can call simple functions to create new pokemon with a name or type from the Pokemon Series from any of the 8 generations. You can call PokemonGenerator.pokemon() to get a random pokemon hash for you to use in you application along with being able to get the moves for that specific pokemon by its name a easy to work with array. If you wish to learn more on how to PokemonGenerator Gem please visit my Homepage.
Sinatra-rraoute provides `gget'/`ppost'/`ddelete'/... methods which work just like Sinatra's built-in `get'/`post'/`delete'/... methods, but which map named routes to functions so that they can be referenced in redirects etc. The `path' helper will return a route for a certain route name and the given values for this route and comes in handy in both, the controller/model component of the application, and the view where you can use it to render links, assets URLs, AJAX calls... The nestable `nnamespace' method is useful for API versioning and does not interfere with other namespace extensions for Sinatra.
The class gives you a search function, which takes a hash in form of {:first => first_name, :last => last_name} and returns an array of hashes corresponding to results. you can send an options hash with :form => 'json' to get the results as JSON example: Phonebook.new.search_results(:first => 'Bob', :last => 'Jones') will produce '[{:name=>Jones, Bob, :location=>HUP Medicine Department of 3400 Spruce St, :contact_info=>{Office=>(215) 5555-5555, Cell=>(215) 555-5555, email=>Bob.jones@uphs.upenn.edu}}]' this is an array, even if there is only one result. Can also call Phonebook.search_results(name_hash, options)
cnuregexp allows tags to be placed inside a regex which function as labels for the matches. The matches within the MatchData object can then be accessed like a hash with the tag name as the key. cnuregexp also provides a greedy match which will return an array of all matches rather than just the first match. cnuregexp can also extract various data from an xml tag with the Regexp.xml_tag method. It uses Regexps to get the tag name, the attributes and their values, the tag content, and any other relevant data from an xml string. Lastly, cnuregexp allows commonly used regular expressions to be stored in a config file(lib/cnuregexp_config.yml) and accessed with Regexp.regular_expression_name notation eg. Regexp.ssn, Regexp.email_address. cnuregexp comes preloaded with a few common regular expressions which are located in lib/cnuregexp_config.yml.
This is a nice and simple full Rails Engine where use can authorize Password before continue to a Rails Controller action. Basically In high secure web site like Banking or HealthCare domain before get enter into Rails Controller action It will ask for password before continue. The main function of that gem is in a link you need to specify a css class and controller name. When user will click the link a Password Confirmation pop up appear and after validating your password only it will give you the access to that respective controller action.
The purpose of this gem is to prevent directly running the inherited methods you choose to block at either the class or instance level, and instead do one of two things: run an alternative block which may or may not invoke the original method, or simply raise an error message. The error message can be customized. The original method can still be called under a different name. The entire object or class can return "unproxied" versions of themselves to preserve the original functionality. This was originally created to help enforce the use of interactors over directly calling ActiveRecord methods like create, save, and update. As with any metaprogramming, this gives you plenty of rope to hang yourself if you try to get too "clever". Treat this library like salt; use sparingly, because over time its cumulative effect will kill you :)
# XQuery [](https://gitter.im/JelF/xquery?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [](https://travis-ci.org/JelF/xquery) [](https://codeclimate.com/github/JelF/xquery) [](https://codeclimate.com/github/JelF/xquery/coverage) [](https://codeclimate.com/github/JelF/xquery) XQuery is designed to replace boring method call chains and allow to easier convert it in a builder classes ## Usage of `XQuery` function `XQuery` is a shortcat to `XQuery::Generic.with` ``` r = XQuery(''.html_safe) do |q| # similar to tap q << 'bla bla bla' q << 'bla bla bla' # using truncate q.truncate(15) # real content (q.send(:query)) mutated q << '!' end r # => "bla bla blab...!" ``` ## Usage of `XQuery::Abstract` I designed this gem to help me with `ActiveRecord` Queries, so i inherited `XQuery::Abstract` and used it's powers. It provides the following features ### `wrap_method` and `wrap_methods` when you call each of this methods they became automatically wrapped (`XQuery::Abstract` basically wraps all methods query `#respond_to?`) It means, that there are instance methods with same name defined and will change a `#query` to their call result. ``` self.query = query.foo(x) # is basically the same as foo(x) # when `wrap_method :foo` called ``` You can also specify new name using `wrap_method :foo, as: :bar` syntax ### `q` object `q` is a proxy object which holds all of wrapped methods, but not methods you defined inside your class. E.g. i have defined `wrap_method(:foo)`, but also delegated `#foo` to some another object. If i call `q.foo`, i will get wrapped method. Note, that if you redefine `#__foo` method, q.foo will call it instead of normal work. You can add additional methods to `q` using something like `alias_on_q :foo`. I used it with `kaminary` and it was useful ``` def page=(x) apply { |query| query.page(x) } end alias_on_q :page= def page query.current_page end alias_on_q :page ``` ### `query_superclass` You should specify `query_superclass` class_attribute to inherit `XQuery::Abstract`. Whenever `query.is_a?(query_superclass)` evaluate to false, you will get `XQuery::QuerySuperclassChanged` exception. It can save you much time when your class misconfigured. E.g. you are using `select!` and it returns `nil`, because why not? ### `#apply` method `#apply` does exact what it source tells ``` # yields query inside block # @param block [#to_proc] # @return [XQuery::Abstract] self def apply(&block) self.query = block.call(query) self end ``` It is usefull to merge different queries. ### `with` class method You can get XQuery functionality even you have not defined a specific class (You are still have to inherit XQuery::Abstract to use it) You can see it in this document when i described `XQuery` function. Note, that it yields a class instance, not `q` object. It accepts any arguments, they will be passed to a constructor (except block) ### `execute` method Preferred way to call public instance methods. Resulting query would be returned
Ame Ame provides a simple command-line interface API for Ruby¹. It can be used to provide both simple interfaces like that of ‹rm›² and complex ones like that of ‹git›³. It uses Ruby’s own classes, methods, and argument lists to provide an interface that is both simple to use from the command-line side and from the Ruby side. The provided command-line interface is flexible and follows commond standards for command-line processing. ¹ See http://ruby-lang.org/ ² See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/rm.html ³ See http://git-scm.com/docs/ § Usage Let’s begin by looking at two examples, one where we mimic the POSIX¹ command-line interface to the ‹rm› command. Looking at the entry² in the standard, ‹rm› takes the following options: = -f. = Do not prompt for confirmation. = -i. = Prompt for confirmation. = -R. = Remove file hierarchies. = -r. = Equivalent to /-r/. It also takes the following arguments: = FILE. = A pathname or directory entry to be removed. And actually allows one or more of these /FILE/ arguments to be given. We also note that the ‹rm› command is described as a command to “remove directory entries”. ¹ See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/contents.html ² See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/rm.html Let’s turn this specification into one using Ame’s API. We begin by adding a flag for each of the options listed above: class Rm < Ame::Root flag 'f', '', false, 'Do not prompt for confirmation' flag 'i', '', nil, 'Prompt for confirmation' do |options| options['f'] = false end flag 'R', '', false, 'Remove file hierarchies' flag 'r', '', nil, 'Equivalent to -R' do |options| options['r'] = true end A flag¹ is a boolean option that doesn’t take an argument. Each flag gets a short and long name, where an empty name means that there’s no corresponding short or long name for the flag, a default value (true, false, or nil), and a description of what the flag does. Each flag can also optionally take a block that can do further processing. In this case we use this block to modify the Hash that maps option names to their values passed to the block to set other flags’ values than the ones that the block is associated with. As these flags (‘i’ and ‘r’) aren’t themselves of interest, their default values have been set to nil, which means that they won’t be included in the Hash that maps option names to their values when passed to the method. ¹ See http://disu.se/software/ame-1.0/api/user/Ame/Class#flag-class-method There are quite a few other kinds of options besides flags that can be defined using Ame, but flags are all that are required for this example. We’ll get to the other kinds in later examples. Next we add a “splus” argument. splus 'FILE', String, 'File to remove' A splus¹ argument is like a Ruby “splat”, that is, an Array argument at the end of the argument list to a method preceded by a star, except that a splus requires at least one argument. A splus argument gets a name for the argument (‹FILE›), the type of argument it represents (String), and a description. ¹ See http://disu.se/software/ame-1.0/api/user/Ame/Class#splus-class-method Then we add a description of the command (method) itself: description 'Remove directory entries' Descriptions¹ will be used in help output to assist the user in using the command. ¹ See http://disu.se/software/ame-1.0/api/user/Ame/Class#description-class-method Finally, we add the Ruby method that’ll implement the command (all preceding code included here for completeness): class Rm < Ame::Root version '1.0.0' flag 'f', '', false, 'Do not prompt for confirmation' flag 'i', '', nil, 'Prompt for confirmation' do |options| options['f'] = false end flag 'R', '', false, 'Remove file hierarchies' flag 'r', '', nil, 'Equivalent to -R' do |options| options['r'] = true end splus 'FILE', String, 'File to remove' description 'Remove directory entries' def rm(files, options = {}) require 'fileutils' FileUtils.send options['R'] ? :rm_r : :rm, [first] + rest, :force => options['f'] end end Actually, another bit of code was also added, namely version '1.0.0' This sets the version¹ String of the command. This information is used when the command is invoked with the “‹--version›” flag. This flag is automatically added, so you don’t need to add it yourself. Another flag, “‹--help›”, is also added automatically. When given, this flag’ll make Ame output usage information of the command. ¹ See http://disu.se/software/ame-1.0/api/user/Ame/Class#version-class-method To actually run the command, all you need to do is invoke Rm.process This’ll invoke the command using the command-line arguments stored in ‹ARGV›, but you can also specify other ones if you want to: Rm.process 'rm', %w[-r /tmp/*] The first argument to #process¹ is the name of the method to invoke, which defaults to ‹File.basename($0)›, and the second argument is an Array of Strings that should be processed as command-line arguments passed to the command. ¹ See http://disu.se/software/ame-1.0/api/user/Ame/Class#process-class-method If you’d store the complete ‹Rm› class defined above in a file called ‹rm› and add ‹#! /usr/bin/ruby -w› at the beginning and ‹Rm.process› at the end, you’d have a fully functional ‹rm› command (after making it executable). Let’s see it in action: % rm --help Usage: rm [OPTIONS]... FILE... Remove directory entries Arguments: FILE... File to remove Options: -R Remove file hierarchies -f Do not prompt for confirmation --help Display help for this method -i Prompt for confirmation -r Equivalent to -R --version Display version information % rm --version rm 1.0.0 Some commands are more complex than ‹rm›. For example, ‹git›¹ has a rather complex command-line interface. We won’t mimic it all here, but let’s introduce the rest of the Ame API using a fake ‹git› clone as an example. ¹ See http://git-scm.com/docs/ ‹Git› uses sub-commands to achieve most things. Implementing sub-commands with Ame is done using a “dispatch”. We’ll discuss dispatches in more detail later, but suffice it to say that a dispatch delegates processing to a child class that’ll handle the sub-command in question. We begin by defining our main ‹git› command using a class called ‹Git› under the ‹Git::CLI› namespace: module Git end class Git::CLI < Ame::Root version '1.0.0' class Git < Ame::Class description 'The stupid content tracker' def initialize; end We’re setting things up to use the ‹Git› class as a dispatch in the ‹Git::CLI› class. The description on the ‹initialize› method will be used as a description of the ‹git› dispatch command itself. Next, let’s add the ‹format-patch›¹ sub-command: description 'Prepare patches for e-mail submission' flag ?n, 'numbered', false, 'Name output in [PATCH n/m] format' flag ?N, 'no-numbered', nil, 'Name output in [PATCH] format' do |options| options['numbered'] = false end toggle ?s, 'signoff', false, 'Add Signed-off-by: line to the commit message' switch '', 'thread', 'STYLE', nil, Ame::Types::Enumeration[:shallow, :deep], 'Controls addition of In-Reply-To and References headers' flag '', 'no-thread', nil, 'Disables addition of In-Reply-To and Reference headers' do |options, _| options.delete 'thread' end option '', 'start-number', 'N', 1, 'Start numbering the patches at N instead of 1' multioption '', 'to', 'ADDRESS', String, 'Add a To: header to the email headers' optional 'SINCE', 'N/A', 'Generate patches for commits after SINCE' def format_patch(since = '', options = {}) p since, options end ¹ See http://git-scm.com/docs/git-format-patch/ We’re using quite a few new Ame commands here. Let’s look at each in turn: toggle ?s, 'signoff', false, 'Add Signed-off-by: line to the commit message' A “toggle”¹ is a flag that also has an inverse. Beyond the flags ‘s’ and “signoff”, the toggle also defines “no-signoff”, which will set “signoff” to false. This is useful if you want to support configuration files that set “signoff”’s default to true, but still allow it to be overridden on the command line. ¹ See http://disu.se/software/ame-1.0/api/user/Ame/Class#toggle-class-method When using the short form of a toggle (and flag and switch), multiple ones may be juxtaposed after the initial one. For example, “‹-sn›” is equivalent to “‹-s -n›” to “git format-patch›”. switch '', 'thread', 'STYLE', nil, Ame::Types::Enumeration[:shallow, :deep], 'Controls addition of In-Reply-To and References headers' A “switch”¹ is an option that takes an optional argument. This allows you to have separate defaults for when the switch isn’t present on the command line and for when it’s given without an argument. The third argument to a switch is the name of the argument. We’re also introducing a new concept here in ‹Ame::Types::Enumeration›. An enumeration² allows you to limit the allowed input to a set of Symbols. An enumeration also has a default value in the first item to its constructor (which is aliased as ‹.[]›). In this case, the “thread” switch defaults to nil, but, when given, will default to ‹:shallow› if no argument is given. If an argument is given it must be either “shallow” or “deep”. A switch isn’t required to take an enumeration as its argument default and can take any kind of default value for its argument that Ame knows how to handle. We’ll look at this in more detail later, but know that the type of the default value will be used to inform Ame how to parse a command-line argument into a Ruby value. An argument to a switch must be given, in this case, as “‹--thread=deep›” on the command line. ¹ See http://disu.se/software/ame-1.0/api/user/Ame/Class#switch-class-method ² See http://disu.se/software/ame-1.0/api/user/Ame/Types/Enumeration/ option '', 'start-number', 'N', 1, 'Start numbering the patches at N instead of 1' An “option”¹ is an option that takes an argument. The argument must always be present and may be given, in this case, as “‹--start-number=2›” or “‹--start-number 2›” on the command line. For a short-form option, anything that follows the option is seen as an argument, so assuming that “start-number” also had a short name of ‘S’, “‹-S2›” would be equivalent to “‹-S 2›”, which would be equivalent to “‹--start-number 2›”. Note that “‹-snS2›” would still work as expected. ¹ See http://disu.se/software/ame-1.0/api/user/Ame/Class#option-class-method multioption '', 'to', 'ADDRESS', String, 'Add a To: header to the email headers' A “multioption”¹ is an option that takes an argument and may be repeated any number of times. Each argument will be added to an Array stored in the Hash that maps option names to their values. Instead of taking a default argument, it takes a type for the argument (String, in this case). Again, types are used to inform Ame how to parse command-line arguments into Ruby values. ¹ See http://disu.se/software/ame-1.0/api/user/Ame/Class#multioption-class-method optional 'SINCE', 'N/A', 'Generate patches for commits after SINCE' An “optional”¹ argument is an argument that isn’t required. If it’s not present on the command line it’ll get its default value (the String ‹'N/A'›, in this case). ¹ See http://disu.se/software/ame-1.0/api/user/Ame/Class#optional-class-method We’ve now covered all kinds of options and one new kind of argument. There are three more types of argument (one that we’ve already seen and two new) that we’ll look into now: “argument”, “splat”, and “splus”. description 'Annotate file lines with commit information' argument 'FILE', String, 'File to annotate' def annotate(file) p file end An “argument”¹ is an argument that’s required. If it’s not present on the command line, an error will be raised (and by default reported to the terminal). As it’s required, it doesn’t take a default, but rather a type. ¹ See http://disu.se/software/ame-1.0/api/user/Ame/Class#argument-class-method description 'Add file contents to the index' splat 'PATHSPEC', String, 'Files to add content from' def add(paths) p paths end A “splat”¹ is an argument that’s not required, but may be given any number of times. The type of a splat is the type of one argument and the type of a splat as a whole is an Array of values of that type. ¹ See http://disu.se/software/ame-1.0/api/user/Ame/Class#splat-class-method description 'Display gitattributes information' splus 'PATHNAME', String, 'Files to list attributes of' def check_attr(paths) p paths end A “splus”¹ is an argument that’s required, but may also be given any number of times. The type of a splus is the type of one argument and the type of a splus as a whole is an Array of values of that type. ¹ See http://disu.se/software/ame-1.0/api/user/Ame/Class#splus-class-method Now that we’ve seen all kinds of options and arguments, let’s look on an additional tool at our disposal, the dispatch¹. class Remote < Ame::Class description 'Manage set of remote repositories' def initialize; end description 'Shows a list of existing remotes' flag 'v', 'verbose', false, 'Show remote URL after name' def list(options = {}) p options end description 'Adds a remote named NAME for the repository at URL' argument 'name', String, 'Name of the remote to add' argument 'url', String, 'URL to the repository of the remote to add' def add(name, url) p name, url end end ¹ See http://disu.se/software/ame-1.0/api/user/Ame/Class#dispatch-class-method Here we’re defining a child class to Git::CLI::Git called “Remote” that doesn’t introduce anything new. Then we set up the dispatch: dispatch Remote, :default => 'list' This adds a method called “remote” to Git::CLI::Git that will dispatch processing of the command line to an instance of the Remote class when “‹git remote›” is seen on the command line. The “remote” method expects an argument that’ll be used to decide what sub-command to execute. Here we’ve specified that in the absence of such an argument, the “list” method should be invoked. We add the same kind of dispatch to Git under Git::CLI: dispatch Git and then we’re done. Here’s all the previous code in its entirety: module Git end class Git::CLI < Ame::Root version '1.0.0' class Git < Ame::Class description 'The stupid content tracker' def initialize; end description 'Prepare patches for e-mail submission' flag ?n, 'numbered', false, 'Name output in [PATCH n/m] format' flag ?N, 'no-numbered', nil, 'Name output in [PATCH] format' do |options| options['numbered'] = false end toggle ?s, 'signoff', false, 'Add Signed-off-by: line to the commit message' switch '', 'thread', 'STYLE', nil, Ame::Types::Enumeration[:shallow, :deep], 'Controls addition of In-Reply-To and References headers' flag '', 'no-thread', nil, 'Disables addition of In-Reply-To and Reference headers' do |options, _| options.delete 'thread' end option '', 'start-number', 'N', 1, 'Start numbering the patches at N instead of 1' multioption '', 'to', 'ADDRESS', String, 'Add a To: header to the email headers' optional 'SINCE', 'N/A', 'Generate patches for commits after SINCE' def format_patch(since = '', options = {}) p since, options end description 'Annotate file lines with commit information' argument 'FILE', String, 'File to annotate' def annotate(file) p file end description 'Add file contents to the index' splat 'PATHSPEC', String, 'Files to add content from' def add(paths) p paths end description 'Display gitattributes information' splus 'PATHNAME', String, 'Files to list attributes of' def check_attr(paths) p paths end class Remote < Ame::Class description 'Manage set of remote repositories' def initialize; end description 'Shows a list of existing remotes' flag 'v', 'verbose', false, 'Show remote URL after name' def list(options = {}) p options end description 'Adds a remote named NAME for the repository at URL' argument 'name', String, 'Name of the remote to add' argument 'url', String, 'URL to the repository of the remote to add' def add(name, url) p name, url end end dispatch Remote, :default => 'list' end dispatch Git end If we put this code in a file called “git” and add ‹#! /usr/bin/ruby -w› at the beginning and ‹Git::CLI.process› at the end, you’ll have a very incomplete git command-line interface on your hands. Let’s look at what some of its ‹--help› output looks like: % git --help Usage: git [OPTIONS]... METHOD [ARGUMENTS]... The stupid content tracker Arguments: METHOD Method to run [ARGUMENTS]... Arguments to pass to METHOD Options: --help Display help for this method --version Display version information Methods: add Add file contents to the index annotate Annotate file lines with commit information check-attr Display gitattributes information format-patch Prepare patches for e-mail submission remote Manage set of remote repositories % git format-patch --help Usage: git format-patch [OPTIONS]... [SINCE] Prepare patches for e-mail submission Arguments: [SINCE=N/A] Generate patches for commits after SINCE Options: -N, --no-numbered Name output in [PATCH] format --help Display help for this method -n, --numbered Name output in [PATCH n/m] format --no-thread Disables addition of In-Reply-To and Reference headers -s, --signoff Add Signed-off-by: line to the commit message --start-number=N Start numbering the patches at N instead of 1 --thread[=STYLE] Controls addition of In-Reply-To and References headers --to=ADDRESS* Add a To: header to the email headers % git remote --help Usage: git remote [OPTIONS]... [METHOD] [ARGUMENTS]... Manage set of remote repositories Arguments: [METHOD=list] Method to run [ARGUMENTS]... Arguments to pass to METHOD Options: --help Display help for this method Methods: add Adds a remote named NAME for the repository at URL list Shows a list of existing remotes § API The previous section gave an introduction to the whole user API in an informal and introductory way. For an indepth reference to the user API, see the {user API documentation}¹. ¹ See http://disu.se/software/ame-1.0/api/user/Ame/ If you want to extend the API or use it in some way other than as a command-line-interface writer, see the {developer API documentation}¹. ¹ See http://disu.se/software/ame-1.0/api/developer/Ame/ § Financing Currently, most of my time is spent at my day job and in my rather busy private life. Please motivate me to spend time on this piece of software by donating some of your money to this project. Yeah, I realize that requesting money to develop software is a bit, well, capitalistic of me. But please realize that I live in a capitalistic society and I need money to have other people give me the things that I need to continue living under the rules of said society. So, if you feel that this piece of software has helped you out enough to warrant a reward, please PayPal a donation to now@disu.se¹. Thanks! Your support won’t go unnoticed! ¹ Send a donation: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=now@disu.se&item_name=Ame § Reporting Bugs Please report any bugs that you encounter to the {issue tracker}¹. ¹ See https://github.com/now/ame/issues § Authors Nikolai Weibull wrote the code, the tests, the documentation, and this README. § Licensing Ame is free software: you may redistribute it and/or modify it under the terms of the {GNU Lesser General Public License, version 3}¹ or later², as published by the {Free Software Foundation}³. ¹ See http://disu.se/licenses/lgpl-3.0/ ² See http://gnu.org/licenses/ ³ See http://fsf.org/
== Confidently Build Terminal Apps Rooibos[https://rooibos.run] helps you build interactive terminal applications. Keep your code understandable and testable as it scales. Rooibos handles keyboard, mouse, and async work so you can focus on behavior and user experience. gem install rooibos <i>Currently in beta. APIs may change before 1.0.</i> === Get Started in Seconds rooibos new my_app cd my_app rooibos run That's it. You have a working app with keyboard navigation, mouse support, and clickable buttons. Open <tt>lib/my_app.rb</tt> to make it your own. --- === The Pattern \Rooibos uses Model-View-Update, the architecture behind Elm[https://guide.elm-lang.org/architecture/], Redux[https://redux.js.org/], and {Bubble Tea}[https://github.com/charmbracelet/bubbletea]. State lives in one place. Updates flow in one direction. The runtime handles rendering and runs background work for you. --- === Hello, MVU The simplest \Rooibos app. Press any key to increment the counter. Press <tt>Ctrl</tt>+<tt>C</tt> to quit. require "rooibos" module Counter # Init: How do you create the initial model? Init = -> { 0 } # View: What does the user see? View = -> (model, tui) { tui.paragraph(text: <<~END) } Current count: #{model}. Press any key to increment. Press Ctrl+C to quit. END # Update: What happens when things change? Update = -> (message, model) { if message.ctrl_c? Rooibos::Command.exit elsif message.key? model + 1 end } end Rooibos.run(Counter) That's the whole pattern: Model holds state, Init creates it, View renders it, and Update changes it. The runtime handles everything else. --- === Your First Real Application A file browser in sixty lines. It opens files, navigates directories, handles errors, styles directories and hidden files differently, and supports vim-style keyboard shortcuts. If you can do this much with this little code, imagine how easy _your_ app will be to build. require "rooibos" module FileBrowser # Model: What state does your app need? Model = Data.define(:path, :entries, :selected, :error) Init = -> { path = Dir.pwd entries = Entries[path] Ractor.make_shareable( # Ensures thread safety Model.new(path:, entries:, selected: entries.first, error: nil)) } View = -> (model, tui) { tui.block( titles: [model.error || model.path, { content: KEYS, position: :bottom, alignment: :right}], borders: [:all], border_style: if model.error then tui.style(fg: :red) else nil end, children: [tui.list(items: model.entries.map(&ListItem[model, tui]), selected_index: model.entries.index(model.selected), highlight_symbol: "", highlight_style: tui.style(modifiers: [:reversed]))] ) } Update = -> (message, model) { return model.with(error: ERROR) if message.error? model = model.with(error: nil) if model.error && message.key? if message.ctrl_c? || message.q? then Rooibos::Command.exit elsif message.home? || message.g? then model.with(selected: model.entries.first) elsif message.end? || message.G? then model.with(selected: model.entries.last) elsif message.up_arrow? || message.k? then Select[:-, model] elsif message.down_arrow? || message.j? then Select[:+, model] elsif message.enter? then Open[model] elsif message.escape? then Navigate[File.dirname(model.path), model] end } private # Lines below this are implementation details KEYS = "↑/↓/Home/End: Select | Enter: Open | Esc: Navigate Up | q: Quit" ERROR = "Sorry, opening the selected file failed." ListItem = -> (model, tui) { -> (name) { modifiers = name.start_with?(".") ? [:dim] : [] fg = :blue if name.end_with?("/") tui.list_item(content: name, style: tui.style(fg:, modifiers:)) } } Select = -> (operator, model) { new_index = model.entries.index(model.selected).public_send(operator, 1) model.with(selected: model.entries[new_index.clamp(0, model.entries.length - 1)]) } Open = -> (model) { full = File.join(model.path, model.selected.delete_suffix("/")) model.selected.end_with?("/") ? Navigate[full, model] : Rooibos::Command.open(full) } Navigate = -> (path, model) { entries = Entries[path] model.with(path:, entries:, selected: entries.first, error: nil) } Entries = -> (path) { Dir.children(path).map { |name| File.directory?(File.join(path, name)) ? "#{name}/" : name }.sort_by { |name| [name.end_with?("/") ? 0 : 1, name.downcase] } } end Rooibos.run(FileBrowser) --- === Batteries Included ==== Commands Applications fetch data, run shell commands, and set timers. \Rooibos Commands run off the main thread and send results back as messages. <b>HTTP requests:</b> Update = -> (message, model) { case message in :fetch_users [model.with(loading: true), Rooibos::Command.http(:get, "/api/users", :got_users)] in { type: :http, envelope: :got_users, status: 200, body: } model.with(loading: false, users: JSON.parse(body)) in { type: :http, envelope: :got_users, status: } model.with(error: "HTTP #{status}") end } <b>Shell commands:</b> Update = -> (message, model) { case message in :list_files Rooibos::Command.system("ls -la", :listed_files) in { type: :system, envelope: :listed_files, stdout:, status: 0 } model.with(files: stdout.lines.map(&:chomp)) in { type: :system, envelope: :listed_files, stderr:, status: } model.with(error: stderr) end } <b>Timers:</b> Update = -> (message, model) { case message in { type: :timer, envelope: :tick, elapsed: } [model.with(frame: model.frame + 1), Rooibos::Command.wait(1.0 / 24, :tick)] end } <b>And more!</b> \Rooibos includes <tt>all</tt>, <tt>batch</tt>, <tt>bubble</tt>, <tt>cancel</tt>, <tt>custom</tt>, <tt>deliver</tt>, <tt>exit</tt>, <tt>http</tt>, <tt>map</tt>, <tt>open</tt>, <tt>system</tt>, <tt>tick</tt>, and <tt>wait</tt> commands. You can also define your own custom commands for complex orchestration. Every command produces a message, and Update handles it the same way. ==== Testing \Rooibos makes TUIs so easy to test, you'll save more time by writing tests than by not testing. <b>Unit test Update, View, and Init.</b> No terminal needed. Test helpers included. def test_moves_selection_down_with_j model = Ractor.make_shareable(FileBrowser::Model.new( path: "/", entries: %w[bin exe lib], selected: "bin", error: nil)) message = RatatuiRuby::Event::Key.new(code: "j") result = FileBrowser::Update.call(message, model) assert_equal "exe", result.selected end <b>Style assertions.</b> Draw to a headless terminal, verify colors and modifiers. def test_directories_are_blue with_test_terminal(60, 10) do model = Ractor.make_shareable(FileBrowser::Model.new( path: "/", entries: %w[file.txt subdir/], selected: "file.txt", error: nil)) widget = FileBrowser::View.call(model, RatatuiRuby::TUI.new) RatatuiRuby.draw { |frame| frame.render_widget(widget, frame.area) } assert_blue(1, 2) # "subdir/" at column 1, row 2 end end <b>System tests.</b> Inject events, run the full app, snapshot the result. def test_selection_moves_down with_test_terminal(120, 30) do Dir.mktmpdir do |dir| FileUtils.touch(File.join(dir, "a")) FileUtils.touch(File.join(dir, "b")) FileUtils.touch(File.join(dir, "c")) inject_key(:down) inject_key(:ctrl_c) # Tests use explicit params to inject deterministic initial state. Rooibos.run( model: Ractor.make_shareable(FileBrowser::Model.new( path: dir, entries: %w[a b c], selected: "a", error: nil)), view: FileBrowser::View, update: FileBrowser::Update ) assert_snapshots("selection_moved_down") do |lines| title = "┌/tmp/test#{'─' * 107}┐" lines.map do |l| l.gsub(/┌#{Regexp.escape(dir)}[^┐]*┐/, title) end end end end end Snapshots record both plain text and ANSI colors. Normalization blocks mask dynamic content (timestamps, temp paths) for cross-platform reproducibility. Run <tt>UPDATE_SNAPSHOTS=1 rake test</tt> to regenerate baselines. ==== Scale Up Large applications decompose into fragments. Each fragment has its own Model, View, Update, and Init. Parents compose children. The pattern scales. The Router DSL eliminates boilerplate: module Dashboard include Rooibos::Router route :stats, to: StatsPanel route :network, to: NetworkPanel receive_events :ctrl_c, -> { Rooibos::Command.exit } only when: -> (_message, model) { !model.modal_open } do receive_events :q, -> { Rooibos::Command.exit } forward_events :s, to: :stats, as: :fetch forward_events :p, to: :network, as: :ping end Update = from_router # ... Model, Init, View below end Declare routes and event handlers. The router generates Update for you. Use guards to ignore messages when needed. ==== CLI The <tt>rooibos</tt> command scaffolds projects and runs applications. rooibos new my_app # Generate project structure rooibos run # Run the app in current directory Generated apps include tests, type signatures, and a working welcome screen with keyboard and mouse support. --- === The Ecosystem \Rooibos builds on RatatuiRuby[https://www.ratatui-ruby.dev], a Rubygem built on Ratatui[https://ratatui.rs]. You get native performance with the joy of Ruby. \Rooibos is one way to manage state and composition. Kit is another. ==== Rooibos[https://www.rooibos.run] Model-View-Update architecture. Inspired by Elm, Bubble Tea, and React + Redux. Your UI is a pure function of state. - Functional programming with MVU - Commands work off the main thread - Messages, not callbacks, drive updates ==== {Kit}[https://sr.ht/~kerrick/ratatui_ruby/#chapter-3-the-object-path--kit] (Coming Soon) Component-based architecture. Encapsulate state, input handling, and rendering in reusable pieces. - OOP with stateful components - Separate UI state from domain logic - Built-in focus management & click handling Both use the same widget library and rendering engine. Pick the paradigm that fits your brain. --- === Links [Get Started] {Getting Started}[https://www.rooibos.run/docs/trunk/doc/getting_started/index_md.html], {Tutorial}[https://www.rooibos.run/docs/trunk/doc/tutorial/index_md.html], {Examples}[https://www.rooibos.run/docs/trunk/examples/app_fractal_dashboard/README_md.html] [Coming From...] {React/Redux}[https://www.rooibos.run/docs/trunk/doc/getting_started/for_react_developers_md.html], {BubbleTea}[https://www.rooibos.run/docs/trunk/doc/getting_started/for_go_developers_md.html], {Textual}[https://www.rooibos.run/docs/trunk/doc/getting_started/for_python_developers_md.html] [Learn More] {Essentials}[https://www.rooibos.run/docs/trunk/doc/essentials/index_md.html], {Scaling Up}[https://www.rooibos.run/docs/trunk/doc/scaling_up/index_md.html], {Best Practices}[https://www.rooibos.run/docs/trunk/doc/best_practices/index_md.html], {Troubleshooting}[https://www.rooibos.run/docs/trunk/doc/troubleshooting/index_md.html] [Community] {Forum}[https://forum.setdef.com/c/rooibos], {Announcements}[https://forum.setdef.com/tags/c/rooibos/announcement], {Bug Tracker}[https://forum.setdef.com/tags/c/rooibos/bug], {Contribution Guide}[https://github.com/setdef/Rooibos/blob/trunk/CONTRIBUTING.md], {Code of Conduct}[https://github.com/setdef/Rooibos/blob/trunk/CODE_OF_CONDUCT.md] --- [Website] https://rooibos.run [Source] https://github.com/setdef/Rooibos [RubyGems] https://rubygems.org/gems/rooibos © 2026 Kerrick Long · Library: LGPL-3.0-or-later · Website: CC-BY-NC-ND-4.0 · Snippets: MIT-0
== README.md: #ScheduledResource This gem is for displaying how things are used over time -- a schedule for a set of "resources". You can configure the elements of the schedule and there are utilities and protocols to connect them: - Configuration (specification and management), - Query interfaces (a REST-like API and internal protocols to query the models), and - A basic Rails controller implementation. We have a way to configure the schedule, internal methods to generate the data, and a way to retrieve data from the client. However this gem is largely view-framework agnostic. We could use a variety of client-side packages or even more traditional Rails view templates to generate HTML. In any case, to get a good feel in a display like this we need some client-side code. The gem includes client-side modules to: - Manage <b>time and display geometries</b> with "infinite" scroll along the time axis. - <b>Format display cells</b> in ways specific to the resource models. - <b>Update text justification</b> as the display is scrolled horizontally. ## Configuration A **scheduled resource** is something that can be used for one thing at a time. So if "Rocky & Bullwinkle" is on channel 3 from 10am to 11am on Saturday, then 'channel 3' is the <u>resource</u> and that showing of the episode is a <u>resource-use</u> block. Resources and use-blocks are typically Rails models. Each resource and its use-blocks get one row in the display. That row has a label to the left with some timespan visible on the rest of the row. Something else you would expect see in a schedule would be headers and labels -- perhaps one row with the date and another row with the hour. Headers and labels also fit the model of resources and use-blocks. Basic timezone-aware classes (ZTime*) for those are included in this gem. ### Config File The schedule configuration comes from <tt>config/resource_schedule.yml</tt> which has three top-level sections: - ResourceKinds: A hash where the key is a Resource and the value is a UseBlock. (Both are class names), - Resources: A list where each item is a Resource Class followed by one or more resource ids, and - visibleTime: The visible timespan of the schedule in seconds. The example file <tt>config/resource_schedule.yml</tt> (installed when you run <tt>schedulize</tt>) should be enough to display a two-row schedule with just the date above and the hour below. Of course you can monkey-patch or subclass these classes for your own needs. ### The schedule API The 'schedule' endpoint uses parameters <tt>t1</tt> and <tt>t2</tt> to specify a time interval for the request. A third parameter <tt>inc</tt> allows an initial time window to be expanded without repeating blocks that span those boundaries. The time parameters _plus the configured resources_ define the data to be returned. ### More About Configuration Management The <b>ScheduledResource</b> class manages resource and use-block class names, id's and labels for a schedule according to the configuration file. A ScheduledResource instance ties together: 1. A resource class (eg TvStation), 2. An id (a channel number in this example), and 3. Strings and other assets that will go into the DOM. The id is used to - select a resource _instance_ and - select instances of the _resource use block_ class (eg Program instances). The id _could_ be a database id but more often is something a little more suited to human use in the configuration. In any case it is used by model class method <tt>(resource_use_block_class).get_all_blocks()</tt> to select the right use-blocks for the resource. A resource class name and id are are joined with a '_' to form a tag that also serves as an id for the DOM. Once the configuration yaml is loaded that data is maintained in the session structure. Of course having a single configuration file limits the application's usefulness. A more general approach would be to have a user model with login and configuration would be associated with the user. ## Installation Add this line to your application's Gemfile: ```ruby gem 'scheduled_resource' ``` And then execute: $ bundle Or install it yourself as: $ gem install scheduled_resource Then from your application's root execute: $ schedulize . This will install a few image placeholders, client-side modules and a stylesheet under <tt>vendor/assets</tt>, an example configuration in <tt>config/resource_schedule.yml</tt> and an example controller in <tt>app/controllers/schedule_controller.rb</tt>. Also, if you use $ bundle show scheduled_resource to locate the installed source you can browse example classes <tt>lib/z_time_*.rb</tt> and the controller helper methods in <tt>lib/scheduled_resource/helper.rb</tt> ## Testing This gem also provides for a basic test application using angularjs to display a minimal but functional schedule showing just the day and hour headers in two different timezones (US Pacific and Eastern). Proceed as follows, starting with a fresh Rails app: $ rails new test_sr As above, add the gem to the Gemfile, then $ cd test_sr $ bundle $ schedulize . Add lines such as these to <tt>config/routes.rb</tt> get "/schedule/index" => "schedule#index" get "/schedule" => "schedule#schedule" Copy / merge these files from the gem source into the test app: $SR_SRC/app/views/layouts/application.html.erb $SR_SRC/app/views/schedule/index.html.erb $SR_SRC/app/assets/javascripts/{angular.js,script.js,controllers.js} and add <tt>//= require angular</tt> to application.js just below the entries for <tt>jquery</tt>. After you run the server and browse to http://0.0.0.0:3000/schedule/index you should see the four time-header rows specified by the sample config file. ## More Examples A better place to see the use of this gem is at [tv4](https://github.com/emeyekayee/tv4). Specifically, models <tt>app/models/event.rb</tt> and <tt>app/models/station.rb</tt> give better examples of implementing the ScheduledResource protocol and adapting to a db schema organized along somewhat different lines. ## Contributing 1. Fork it ( https://github.com/emeyekayee/scheduled_resource/fork ) 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create a new Pull Request
http://www.engineyard.com/blog/2010/extending-rails-3-with-railties/ http://www.igvita.com/2010/08/04/rails-3-internals-railtie-creating-plugins/ h1. Morning Glory Morning Glory is comprised of a rake task and helper methods that manages the deployment of static assets into an Amazon CloudFront CDN's S3 Bucket, improving the performance of static assets on your Rails web applications. _NOTE: You will require an Amazon Web Services (AWS) account in order to use this gem. Specially: S3 for storing the files you wish to distribute, and CloudFront for CDN distribution of those files._ This version of Morning Glory works with Rails 3.x and Ruby 1.9.x h2. What does it do? Morning Glory provides an easy way to deploy Ruby on Rails application assets to the Amazon CloudFront CDN. It solves a number of common issues with S3/CloudFront. For instance, CloudFront won't automatically expire old assets stored on edge nodes when you redeploy new assets (the Cloudfront expiry time is 24 hours minimum). To fix this Morning Glory will automatically namespace asset releases for you, then update all references to those renamed assets within your stylesheets ensuring there are no broken asset links. It also provides a helper method to rewrite all standard Rails asset helper generated URLs to your CloudFront CDN distributions, as well as handling switching between HTTP and HTTPS. Morning Glory was also built with SASS (Syntactically Awesome Stylesheets) in mind. If you use Sass for your stylesheets they will automatically be built before deployment to the CDN. See http://sass-lang.com/ for more information on Sass.s h2. What it doesn't do Morning Glory cannot configure your CloudFront distributions for you automatically. You will manually have to login to your AWS Management Console account, "https://console.aws.amazon.com/cloudfront/home":https://console.aws.amazon.com/cloudfront/home, and set up a distribution pointing to an S3 Bucket. h2. Installation <pre> gem 'morning_glory' </pre> h2. Usage Morning Glory provides it's functionality via rake tasks. You'll need to specify the target rails environment configuration you want to deploy for by using the @RAILS_ENV={env}@ parameter (for example, @RAILS_ENV=production@). <pre> rake morning_glory:cloudfront:deploy RAILS_ENV={YOUR_TARGET_ENVIRONMENT} </pre> h2. Configuration h3. The Morning Glory configuration file, @config/morning_glory.yml@ You can specify a configuration section for every rails environment (production, staging, testing, development). This section can have the following properties defined: <pre> --- production: enabled: true # Is MorningGlory enabled for this environment? bucket: cdn.production.foo.com # The bucket to deploy your assets into s3_logging_enabled: true # Log the deployment to S3 revision: "20100317134627" # The revision prefix. This timestamp automatically generateed on deployment delete_prev_rev: true # Delete the previous asset release (save on S3 storage space) </pre> h3. The Amazon S3 authentication keys configuration file, @config/s3.yml@ This file provides the access credentials for your Amazon AWS S3 account. You can configure keys for all your environments (production, staging, testing, development). <pre> --- production: access_key_id: YOUR_ACCESS_KEY secret_access_key: YOUR_SECRET_ACCESS_KEY </pre> Note: If you are deploying your system to Heroku, you can configure your Amazon AWS S3 information with the environment variables S3_KEY and S3_SECRET instead of using a configuration file. h3. Set up an asset_host For each environment that you'd like to utilise the CloudFront CDN for you'll need to define the asset_host within the @config/environments/{ENVIRONMENT}.rb@ configuration file. As of June 2010 AWS supports HTTPS requests on the CloudFront CDN, so you no longer have to worry about switching servers. (Yay!) h4. Example config/environments/production.rb @asset_host@ snippet: Here we're targeting a CNAME domain with HTTP support. <pre> ActionController::Base.asset_host = Proc.new { |source, request| if request.ssl? "#{request.protocol}#{request.host_with_port}" else "#{request.protocol}assets.example.com" end } </pre> h3. Why do we have to use a revision-number/namespace/timestamp? Once an asset has been deployed to the Amazon Cloudfront edge servers it cannot be modified - the version exists until it expires (minimum of 24 hours). To get around this we need to prefix the asset path with a revision of some sort - in MorningGlory's case we use a timestamp. That way you can deploy many times during a 24 hour period and always have your latest revision available on your web site. h2. Dependencies h3. AWS S3 Required for uploading the assets to the Amazon Web Services S3 buckets. See "http://amazon.rubyforge.org/":http://amazon.rubyforge.org/ for more documentation on installation. h2. About the name Perhaps not what you'd expect; a "Morning Glory":http://en.wikipedia.org/wiki/Morning_Glory_cloud is a rare cloud formation observed by glider pilots in Australia (see my side project, "YourFlightLog.com for flight-logging software for paraglider and hang-glider pilots":http://www.yourflightlog.com, from which the Morning Glory plugin was originally extracted). Copyright (c) 2010 "@AdamBurmister":http://twitter.com/adamburmister/, released under the MIT license
No description provided.
No description provided.
No description provided.
No description provided.
No description provided.
No description provided.
No description provided.
No description provided.
No description provided.
No description provided.
No description provided.
No description provided.