Wordfreq: Text Corpus Calculation in Javascript

wordfreq

Text corpus calculation in Javascript. Supports Chinese, English. See demo.

This library is a spin-off project from HTML5 Word Cloud.

Simple usage

Load wordfreq.js script to the web page, and run:

// Create an options object for initialization
var options = {
  workerUrl: 'path/to/wordfreq.worker.js' };
// Initialize and run process() function
var wordfreq = WordFreq(options).process(text, function (list) {
  // console.log the list returned in this callback.
  console.log(list);
});

WordFreq() methods are chainable, for example,

// Process 3 strings and get corpus of all the texts.
WordFreq(options)
  .process(text).process(text2).process(text3)
  .getList(function (list) {
    console.log(list);
  });

To use this library synchronously, load wordfreq.worker.js and use the WordFreqSync interface. Check API.md for available options and methods.

Command-line interface

Command-line interface is available, powered by Node.js. To install globally, run

npm install -g wordfreq

Example usage:

wordfreq ~/mypost.txt | less
cat ~/mypost.txt | wordfreq - | less

Algorithm

Corpus is calculated with a simple N-gram algorithm and sub-string filter. Here is an article in Traditional Chinese on how HTML5 Word Cloud is being done.

Porter Stemming Algorithm is included for processing English.

Testing

To run tests, first you would need to pull the required QUnit library by running

git submodule init
git submodule update

Then, start a localhost HTTP server, for example,

python -m SimpleHTTPServer 8009

Point your browser to http://localhost:8009/test/ to start testing.

You may also run the tests with PhantomJS by running

phantomjs test/qunit/addons/phantomjs/runner.js http://localhost:8009/test/

You will find all the information you need to write testcases on the QUnit website. All non-trivial code submission are expected to accompany with testcases.

Known IE10 issue: Looks like IE10 suffers from the same issue with Firefox <= 17, where Web Worker will choke and couldn't finish the entire test suite.

Download Details:

Author: Timdream
Source Code: https://github.com/timdream/wordfreq 
License: MIT license

#javascript #html #text 

Wordfreq: Text Corpus Calculation in Javascript
Nat  Grady

Nat Grady

1659749940

GGrepel: Repel Overlapping Text Labels Away From Each Other

ggrepel

Overview

ggrepel provides geoms for ggplot2 to repel overlapping text labels:

  • geom_text_repel()
  • geom_label_repel()

Text labels repel away from each other, away from data points, and away from edges of the plotting area.

library(ggrepel)
ggplot(mtcars, aes(wt, mpg, label = rownames(mtcars))) +
  geom_text_repel() +
  geom_point(color = 'red') +
  theme_classic(base_size = 16)

Installation

# The easiest way to get ggrepel is to install it from CRAN:
install.packages("ggrepel")

# Or get the the development version from GitHub:
# install.packages("devtools")
devtools::install_github("slowkow/ggrepel")

Usage

See the examples page to learn more about how to use ggrepel in your project.

Contributing

Please submit an issue to report bugs or ask questions.

Please contribute bug fixes or new features with a pull request to this repository.

Author: Slowkow
Source Code: https://github.com/slowkow/ggrepel 
License: GPL-3.0 license

#r #visualization #text 

GGrepel: Repel Overlapping Text Labels Away From Each Other
Beth  Cooper

Beth Cooper

1659694200

Easy Activity Tracking for Models, Similar to Github's Public Activity

PublicActivity

public_activity provides easy activity tracking for your ActiveRecord, Mongoid 3 and MongoMapper models in Rails 3 and 4.

Simply put: it can record what happens in your application and gives you the ability to present those recorded activities to users - in a similar way to how GitHub does it.

!! WARNING: README for unreleased version below. !!

You probably don't want to read the docs for this unreleased version 2.0.

For the stable 1.5.X readme see: https://github.com/chaps-io/public_activity/blob/1-5-stable/README.md

About

Here is a simple example showing what this gem is about:

Example usage

Tutorials

Screencast

Ryan Bates made a great screencast describing how to integrate Public Activity.

Tutorial

A great step-by-step guide on implementing activity feeds using public_activity by Ilya Bodrov.

Online demo

You can see an actual application using this gem here: http://public-activity-example.herokuapp.com/feed

The source code of the demo is hosted here: https://github.com/pokonski/activity_blog

Setup

Gem installation

You can install public_activity as you would any other gem:

gem install public_activity

or in your Gemfile:

gem 'public_activity'

Database setup

By default public_activity uses Active Record. If you want to use Mongoid or MongoMapper as your backend, create an initializer file in your Rails application with the corresponding code inside:

For Mongoid:

# config/initializers/public_activity.rb
PublicActivity.configure do |config|
  config.orm = :mongoid
end

For MongoMapper:

# config/initializers/public_activity.rb
PublicActivity.configure do |config|
  config.orm = :mongo_mapper
end

(ActiveRecord only) Create migration for activities and migrate the database (in your Rails project):

rails g public_activity:migration
rake db:migrate

Model configuration

Include PublicActivity::Model and add tracked to the model you want to keep track of:

For ActiveRecord:

class Article < ActiveRecord::Base
  include PublicActivity::Model
  tracked
end

For Mongoid:

class Article
  include Mongoid::Document
  include PublicActivity::Model
  tracked
end

For MongoMapper:

class Article
  include MongoMapper::Document
  include PublicActivity::Model
  tracked
end

And now, by default create/update/destroy activities are recorded in activities table. This is all you need to start recording activities for basic CRUD actions.

Optional: If you don't need #tracked but still want the comfort of #create_activity, you can include only the lightweight Common module instead of Model.

Custom activities

You can trigger custom activities by setting all your required parameters and triggering create_activity on the tracked model, like this:

@article.create_activity key: 'article.commented_on', owner: current_user

See this entry http://rubydoc.info/gems/public_activity/PublicActivity/Common:create_activity for more details.

Displaying activities

To display them you simply query the PublicActivity::Activity model:

# notifications_controller.rb
def index
  @activities = PublicActivity::Activity.all
end

And in your views:

<%= render_activities(@activities) %>

Note: render_activities is an alias for render_activity and does the same.

Layouts

You can also pass options to both activity#render and #render_activity methods, which are passed deeper to the internally used render_partial method. A useful example would be to render activities wrapped in layout, which shares common elements of an activity, like a timestamp, owner's avatar etc:

<%= render_activities(@activities, layout: :activity) %>

The activity will be wrapped with the app/views/layouts/_activity.html.erb layout, in the above example.

Important: please note that layouts for activities are also partials. Hence the _ prefix.

Locals

Sometimes, it's desirable to pass additional local variables to partials. It can be done this way:

<%= render_activity(@activity, locals: {friends: current_user.friends}) %>

Note: Before 1.4.0, one could pass variables directly to the options hash for #render_activity and access it from activity parameters. This functionality is retained in 1.4.0 and later, but the :locals method is preferred, since it prevents bugs from shadowing variables from activity parameters in the database.

Activity views

public_activity looks for views in app/views/public_activity.

For example, if you have an activity with :key set to "activity.user.changed_avatar", the gem will look for a partial in app/views/public_activity/user/_changed_avatar.html.(|erb|haml|slim|something_else).

Hint: the "activity." prefix in :key is completely optional and kept for backwards compatibility, you can skip it in new projects.

If you would like to fallback to a partial, you can utilize the fallback parameter to specify the path of a partial to use when one is missing:

<%= render_activity(@activity, fallback: 'default') %>

When used in this manner, if a partial with the specified :key cannot be located it will use the partial defined in the fallback instead. In the example above this would resolve to public_activity/_default.html.(|erb|haml|slim|something_else).

If a view file does not exist then ActionView::MisingTemplate will be raised. If you wish to fallback to the old behaviour and use an i18n based translation in this situation you can specify a :fallback parameter of text to fallback to this mechanism like such:

<%= render_activity(@activity, fallback: :text) %>

i18n

Translations are used by the #text method, to which you can pass additional options in form of a hash. #render method uses translations when view templates have not been provided. You can render pure i18n strings by passing {display: :i18n} to #render_activity or #render.

Translations should be put in your locale .yml files. To render pure strings from I18n Example structure:

activity:
  article:
    create: 'Article has been created'
    update: 'Someone has edited the article'
    destroy: 'Some user removed an article!'

This structure is valid for activities with keys "activity.article.create" or "article.create". As mentioned before, "activity." part of the key is optional.

Testing

For RSpec you can first disable public_activity and add require helper methods in the rails_helper.rb with:

#rails_helper.rb
require 'public_activity/testing'

PublicActivity.enabled = false

In your specs you can then blockwise decide whether to turn public_activity on or off.

# file_spec.rb
PublicActivity.with_tracking do
  # your test code goes here
end

PublicActivity.without_tracking do
  # your test code goes here
end

Documentation

For more documentation go here

Common examples

Set the Activity's owner to current_user by default

You can set up a default value for :owner by doing this:

  1. Include PublicActivity::StoreController in your ApplicationController like this:
class ApplicationController < ActionController::Base
  include PublicActivity::StoreController
end
  1. Use Proc in :owner attribute for tracked class method in your desired model. For example:
class Article < ActiveRecord::Base
  tracked owner: Proc.new{ |controller, model| controller.current_user }
end

Note: current_user applies to Devise, if you are using a different authentication gem or your own code, change the current_user to a method you use.

Disable tracking for a class or globally

If you need to disable tracking temporarily, for example in tests or db/seeds.rb then you can use PublicActivity.enabled= attribute like below:

# Disable p_a globally
PublicActivity.enabled = false

# Perform some operations that would normally be tracked by p_a:
Article.create(title: 'New article')

# Switch it back on
PublicActivity.enabled = true

You can also disable public_activity for a specific class:

# Disable p_a for Article class
Article.public_activity_off

# p_a will not do anything here:
@article = Article.create(title: 'New article')

# But will be enabled for other classes:
# (creation of the comment will be recorded if you are tracking the Comment class)
@article.comments.create(body: 'some comment!')

# Enable it again for Article:
Article.public_activity_on

Create custom activities

Besides standard, automatic activities created on CRUD actions on your model (deactivatable), you can post your own activities that can be triggered without modifying the tracked model. There are a few ways to do this, as PublicActivity gives three tiers of options to be set.

Instant options

Because every activity needs a key (otherwise: NoKeyProvided is raised), the shortest and minimal way to post an activity is:

@user.create_activity :mood_changed
# the key of the action will be user.mood_changed
@user.create_activity action: :mood_changed # this is exactly the same as above

Besides assigning your key (which is obvious from the code), it will take global options from User class (given in #tracked method during class definition) and overwrite them with instance options (set on @user by #activity method). You can read more about options and how PublicActivity inherits them for you here.

Note the action parameter builds the key like this: "#{model_name}.#{action}". You can read further on options for #create_activity here.

To provide more options, you can do:

@user.create_activity action: 'poke', parameters: {reason: 'bored'}, recipient: @friend, owner: current_user

In this example, we have provided all the things we could for a standard Activity.

Use custom fields on Activity

Besides the few fields that every Activity has (key, owner, recipient, trackable, parameters), you can also set custom fields. This could be very beneficial, as parameters are a serialized hash, which cannot be queried easily from the database. That being said, use custom fields when you know that you will set them very often and search by them (don't forget database indexes :) ).

Set owner and recipient based on associations

class Comment < ActiveRecord::Base
  include PublicActivity::Model
  tracked owner: :commenter, recipient: :commentee

  belongs_to :commenter, :class_name => "User"
  belongs_to :commentee, :class_name => "User"
end

Resolve parameters from a Symbol or Proc

class Post < ActiveRecord::Base
  include PublicActivity::Model
  tracked only: [:update], parameters: :tracked_values
  
  def tracked_values
   {}.tap do |hash|
     hash[:tags] = tags if tags_changed?
   end
  end
end

Setup

Skip this step if you are using ActiveRecord in Rails 4 or Mongoid

The first step is similar in every ORM available (except mongoid):

PublicActivity::Activity.class_eval do
  attr_accessible :custom_field
end

place this code under config/initializers/public_activity.rb, you have to create it first.

To be able to assign to that field, we need to move it to the mass assignment sanitizer's whitelist.

Migration

If you're using ActiveRecord, you will also need to provide a migration to add the actual field to the Activity. Taken from our tests:

class AddCustomFieldToActivities < ActiveRecord::Migration
  def change
    change_table :activities do |t|
      t.string :custom_field
    end
  end
end

Assigning custom fields

Assigning is done by the same methods that you use for normal parameters: #tracked, #create_activity. You can just pass the name of your custom variable and assign its value. Even better, you can pass it to #tracked to tell us how to harvest your data for custom fields so we can do that for you.

class Article < ActiveRecord::Base
  include PublicActivity::Model
  tracked custom_field: proc {|controller, model| controller.some_helper }
end

Help

If you need help with using public_activity please visit our discussion group and ask a question there:

https://groups.google.com/forum/?fromgroups#!forum/public-activity

Please do not ask general questions in the Github Issues.


Author: public-activity
Source code: https://github.com/public-activity/public_activity
License: MIT license

#ruby  #ruby-on-rails 

Easy Activity Tracking for Models, Similar to Github's Public Activity
Royce  Reinger

Royce Reinger

1659360674

TTS: A Ruby Gem for Text-to-Speech By using Google Translate Service

tts

Using the Google Translate service as the speech engine, this gem generates a .mp3 voice file from any given string.

Usage

require 'tts'
# Will download "Hello World!.mp3" to your current directory
# Supported languages: ["zh", "en", "it", "fr"]
"Hello World!".to_file "en"

# i18n
"人民代表代表人民".to_file "zh"

# Save the file to a specific location
"Light rain with highs of 5 degrees".to_file "en", "~/weather.mp3"

# Supports large text files, as the gem will batch up the requests to Google (as each request max 100 chars)
text = "People living on the east coast of England have been warned to stay away from their homes because of further high tides expected later. The tidal surge that hit the UK is said to have been the worst for 60 years, with thousands abandoning their homes."
text.to_file "en"

#Direct playback (require mpg123 installed and in PATH with a POSIX system)
"Established in 1853, the University of Melbourne is a public-spirited institution that makes distinctive contributions to society in research, learning and teaching and engagement.".play

#Direct playback in other language (2 times)
 "Oggi il tempo è buono, andiamo in gita di esso.".play("it", 2)

#RTL Arabic language
"اليوم كان الطقس جيدا، ونحن نذهب في نزهة منه.".play("ar")

Direct play dependencies

You need to install `mpg123`

sudo apt-get install mpg123 #for debain based
brew install mpg123 #mac

CLI

tts "ruby is great"   # play the string.
text2mp3 "中国上海天气不错" "zh" #create mp3 file.

Versions

0.4 fixed issue that long text unable to generated.

0.5 added all supported languages, added direct playback feature fixed some broken rspec.

0.7 added CLI support

0.7.1 fixed new google API

Download Details: 

Author: c2h2
Source Code: https://github.com/c2h2/tts 
License: MIT license

#ruby #text #google 

TTS: A Ruby Gem for Text-to-Speech By using Google Translate Service
Royce  Reinger

Royce Reinger

1659345843

Espeak-ruby: Ruby Wrapper for ‘espeak’ and ‘lame’ with Sugar on Top

espeak-ruby

espeak-ruby is a small Ruby API for utilizing espeak and lame to create Text-To-Speech mp3 files or just speak (without saving). See live demo.

Install

Add espeak-ruby to Gemfile

gem "espeak-ruby", require: "espeak"

Examples

# Speaks "YO!"
speech = ESpeak::Speech.new("YO!")
speech.speak # invokes espeak

# Creates hello-de.mp3 file
speech = ESpeak::Speech.new("Hallo Welt", voice: "de")
speech.save("hello-de.mp3") # invokes espeak + lame

# Lists voices
ESpeak::Voice.all.map { |v| v.language } # ["af", "bs", "ca", "cs", "cy", "da", "de", "el", "en", "en-sc", "en-uk", "en-uk-north", "en-uk-rp", "en-uk-wmids", "en-us", "en-wi", "eo", "es", "es-la", "fi", "fr", "fr-be", "grc", "hi", "hr", "hu", "hy", "hy", "id", "is", "it", "jbo", "ka", "kn", "ku", "la", "lv", "mk", "ml", "nci", "nl", "no", "pap", "pl", "pt", "pt-pt", "ro", "ru", "sk", "sq", "sr", "sv", "sw", "ta", "tr", "vi", "zh", "zh-yue"]

# Find particular voice
ESpeak::Voice.find_by_language('en') #<ESpeak::Voice:0x007fe1d3806be8 @language="en", @name="default", @gender="M", @file="default">

Features

Currently only subset of espeak features is supported.

:voice   => 'en'    # use voice file of this name from espeak-data/voices
:pitch   => 50      # pitch adjustment, 0 to 99
:speed   => 170     # speed in words per minute, 80 to 370
:capital => 170     # increase emphasis (pitch) of capitalized words, 1 to 40 (for natural sound, can go higher)

These are default values, and they can be easily overridden:

Speech.new("Zdravo svete", voice: "sr", pitch: 90, speed: 200).speak

Installing dependencies

OS X

brew install espeak lame

Ubuntu

apt-get install espeak lame

Download Details: 

Author: Dejan
Source Code: https://github.com/dejan/espeak-ruby 
License:  MIT License

#ruby #wrapper #text 

Espeak-ruby: Ruby Wrapper for ‘espeak’ and ‘lame’ with Sugar on Top

TextField That Manages The toggle Of Obscure with Flutter

password_text_field

PasswordTextField is a TextField that manages the toggle of obscure.

How to use

Replace your TextField(PasswordTextField) or TextFormField(PasswordTextFormField).

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add password_text_field

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  password_text_field: ^1.0.1

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:password_text_field/password_text_field.dart'; 

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:password_text_field/password_text_field.dart';

void main() {
  runApp(
    const MyApp(),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'password_text_field demo',
      theme: ThemeData.from(
        colorScheme: const ColorScheme.light(),
      ),
      darkTheme: ThemeData.from(
        colorScheme: const ColorScheme.dark(),
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final _formState = GlobalKey<FormState>();
  final _textFormFieldController = TextEditingController();

  final _smallSpace = const SizedBox(height: 8);
  final _mediumSpace = const SizedBox(height: 16);
  final _largeSpace = const SizedBox(height: 32);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Demo Page'),
      ),
      body: Center(
        child: SizedBox(
          width: 320,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              Text(
                'TextField',
                style: Theme.of(context).textTheme.headline6,
              ),
              _smallSpace,
              const PasswordTextField(
                decoration: InputDecoration(
                  border: UnderlineInputBorder(),
                  hintText: 'underline',
                ),
              ),
              _mediumSpace,
              const PasswordTextField(
                decoration: InputDecoration(
                  border: OutlineInputBorder(),
                  hintText: 'outline',
                ),
              ),
              _largeSpace,
              Form(
                key: _formState,
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      'TextFormField',
                      style: Theme.of(context).textTheme.headline6,
                    ),
                    _smallSpace,
                    PasswordTextFormField(
                      controller: _textFormFieldController,
                      validator: (value) {
                        if ((value?.length ?? 0) < 6) {
                          return 'Password must be at least 6 characters';
                        }

                        return null;
                      },
                    ),
                    _mediumSpace,
                    ElevatedButton(
                      onPressed: () {
                        _formState.currentState?.validate();
                      },
                      child: const Text('Check'),
                    )
                  ],
                ),
              )
            ],
          ),
        ),
      ),
    );
  }
} 

Download Details:

Author: koji-1009

Source Code: https://github.com/koji-1009/password_text_field

#flutter  #text 

 TextField That Manages The toggle Of Obscure with Flutter
Royce  Reinger

Royce Reinger

1659254940

Ruby-tesseract-ocr: A Ruby Wrapper Library to The Tesseract-ocr API

ruby-tesseract - Ruby bindings and wrapper

This wrapper binds the TessBaseAPI object through ffi-inline (which means it will work on JRuby too) and then proceeds to wrap said API in a more ruby-esque Engine class.

Making it work

To make this library work you need tesseract-ocr and leptonica libraries and headers and a C++ compiler.

The gem is called tesseract-ocr.

If you're on a distribution that separates the libraries from headers, remember to install the -dev package.

On Debian you will need to install libleptonica-dev and libtesseract-dev.

Examples

Following are some examples that show the functionalities provided by tesseract-ocr.

Basic functionality of tesseract

require 'tesseract'

e = Tesseract::Engine.new {|e|
  e.language  = :eng
  e.blacklist = '|'
}

e.text_for('test/first.png').strip # => 'ABC'

You can pass to #text_for either a path, an IO object, a string containing the image or an object that responds to #to_blob (for example Magick::Image), keep in mind that the format has to be supported by leptonica.

Accessing advanced features

With advanced features you get access to blocks, paragraphs, lines, words and symbols.

Replace level in method names with either block, paragraph, line, word or symbol.

The following kind of accessors need a block to be passed and they pass to the block each Element object. The Element object has various getters to access certain features, I'll talk about them later.

The methods are:

  • each_level
  • each_level_for
  • each_level_at

The following accessors instead return an Array of Elements with cached getters, the getters are cached beacause the values accessible in the Element are linked to the state of the internal API, and that state changes if you access something else.

The methods are:

  • levels
  • levels_for
  • levels_at

Again, to *_for methods you can pass what you can pass to a #text_for.

Each Element object has the following getters:

  • bounding_box, this will return the box where the element is confined into
  • binary_image, this will return the bichromatic image of the element
  • image, this will return the image of the element
  • baseline, this will return the line where the text is with a pair of coordinates
  • orientation, this will return the orientation of the element
  • text, this will return the text of the element
  • confidence, this will return the confidence of correctness for the element

Block elements also have type accessors that specify the type of the block.

Word elements also have font_attributes, from_dictionary? and numeric? getters.

Symbol elements also have superscript?, subscript? and dropcap? getters.

hOCR

require 'tesseract'

e = Tesseract::Engine.new {|e|
  e.language  = :eng
  e.blacklist = '|'
}

puts e.hocr_for('test/first.png')

You can pass to #hocr_for either a path, an IO object, a string containing the image or an object that responds to #to_blob (for example Magick::Image), keep in mind that the format has to be supported by leptonica.

Please note you have to pass #hocr_for the page you want to get the output of as well.

Using the binary

You can also use the shipped executable in the following way:

> tesseract.rb -h
Usage: tesseract [options]
        --path PATH                  datapath to set
    -l, --language LANGUAGE          language to use
    -m, --mode MODE                  mode to use
    -p, --psm MODE                   page segmentation mode to use
    -u, --unlv                       output in UNLV format
    -c, --confidence                 output the mean confidence of the recognition
    -C, --config PATH...             config files to load
    -b, --blacklist LIST             blacklist the following chars
    -w, --whitelist LIST             whitelist the following chars
> tesseract.rb test/first.png 
ABC
> tesseract.rb -c test/first.png 
86

Author: meh
Source Code: https://github.com/meh/ruby-tesseract-ocr 
License: BSD

#ruby #tesseract 

Ruby-tesseract-ocr: A Ruby Wrapper Library to The Tesseract-ocr API
Royce  Reinger

Royce Reinger

1659220500

Apeech2text: A Simple interface to Play with To Convert Speech To Text

Speech2Text

Using the power of ffmpeg/flac/Google and ruby here is a simple interface to play with to convert speech to text.

Using a new undocumentd speech API from Google with the help of this article: mikepultz.com/2011/03/accessing-google-speech-api-chrome-11/

We're able to provide a very simple API in Ruby to decode simple audio to text.

The API from Google is not yet public and so may change. It also seems to be very fragile as more times than not it will return a 500, so the library has retry code built in - for larger audio files 10+ failures may return before a successful result is retrieved…

It also appears that the API only likes smaller audio files so there is a built in chunker that allows us to split the audio up into smaller chunks.

Installation

Add this line to your application's Gemfile:

gem 'speech2text'

And then execute:

$ bundle

Or install it yourself as:

$ gem install speech2text

You must also install the ffmpeg utility on your local machine. If you are using OS X, the easiest way to do this is to install brew. You may need to instal XQuartz before installing ffmpeg:

$ ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go)"
# You may be prompted to install XQuartz. Get it at https://xquartz.macosforge.org
$ brew install ffmpeg

Example

require 'speech'

audio = Speech::AudioToText.new("i-like-pickles.wav")
puts audio.to_text.inspect
=> {"captured_json"=>[["I like pickles", 0.92731786]], "confidence"=>0.92731786}

Command Line

speech2text i-like-pickles.wav
cat i-like-pickles.json
{"captured_json"=>[["I like pickles", 0.92731786]], "confidence"=>0.92731786}

Author: taf2
Source Code: https://github.com/taf2/speech2text 
License: 

#ruby #text 

Apeech2text: A Simple interface to Play with To Convert Speech To Text
Royce  Reinger

Royce Reinger

1659205440

A Ruby Library for Consuming The AT&T Speech API For Speech to Text

att_speech

A Ruby library for consuming the AT&T Speech API for speech to text. API details may be found here.

Installation

gem install att_speech

Usage

require 'att_speech'

att_speech = ATTSpeech.new({ :api_key    => ENV['ATT_SPEECH_KEY'],
                             :secret_key => ENV['ATT_SPEECH_SECRET'],
                             :scope      => 'SPEECH' })

# Read the audio file contents
file_contents = File.read(File.expand_path(File.dirname(File.dirname(__FILE__))) + "/bostonSeltics.wav")

# Blocking operation
p att_speech.speech_to_text(file_contents, type='audio/wav')

# Non-blocking operation with a future, if you have a longer file that requires more processing time
sleep 2
future = att_speech.future(:speech_to_text, file_contents, type='audio/wav')
p future.value

# Non-blocking operation that will call a block when the transcrption is returned
# Note: Remember, this is a concurrent operation so don't pass self and avoid mutable objects in the block
# from the calling context, better to have discreet actions contained in the block, such as inserting in a
# datastore
sleep 2
supervisor = ATTSpeech.supervise({ :api_key    => ENV['ATT_SPEECH_KEY'],
                                   :secret_key => ENV['ATT_SPEECH_SECRET'],
                                   :scope      => 'SPEECH' })
supervisor.future.speech_to_text(file_contents)
# do other stuff here
sleep 5
transcription = supervisor.value # returns immediately if the operation is complete, otherwise blocks until the value is ready

def write_wav_file(audio_bytes)
  file_name = "ret_audio-#{Time.now.strftime('%Y%m%d-%H%M%S')}.wav"
  full_file_name = File.expand_path(File.join(File.dirname(File.dirname(__FILE__)), 'examples', file_name))
  audio_file = File.open(full_file_name, "w")
  audio_file << audio_bytes
  audio_file.close
end

att_text = ATTSpeech.new({ :api_key    => ENV['ATT_SPEECH_KEY'],
                           :secret_key => ENV['ATT_SPEECH_SECRET'],
                           :scope      => 'TTS' })

# Read the text file contents
tfp = File.expand_path(File.join(File.dirname(File.dirname(__FILE__)), 'examples', 'helloWorld.txt'))
txt_contents = File.read(tfp)

audio = att_text.text_to_speech(txt_contents)
write_wav_file(audio)

# Non-blocking operation with a future, if you have a longer file that requires more processing time
sleep 2
future = att_text.future(:text_to_speech, "This is a hello world.", type='text/plain')
write_wav_file(future.value)

Author: Adhearsion
Source Code: https://github.com/adhearsion/att_speech 
License: MIT license

#ruby #api #text 

A Ruby Library for Consuming The AT&T Speech API For Speech to Text

A New Flutter Package That Provide Already Made Text form Field

flutter_text_form_field

A new Flutter package that provide already made text form field

##Usage

[Example] (https://github.com/Destiny-Ed/flutter_text_form_field/blob/main/example/example_app.dart)

To use this package : *add the dependency to your [pubspec.yaml] file

    dependencies:
        flutter:
            sdk : flutter
        flutter_text_form_field: ^0.0.3
    //...
    Example Usage
    //...

import 'package:flutter/material.dart';
import 'package:flutter_text_form_field/flutter_text_form_field.dart';

class Login extends StatefulWidget {
  @override
  _LoginState createState() => _LoginState();
}

class _LoginState extends State<Login> {
  final TextEditingController _emailController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SingleChildScrollView(
        child: Container(
          height: MediaQuery.of(context).size.height,
          width: MediaQuery.of(context).size.width,
          decoration: BoxDecoration(color: Colors.purple),
          child: Column(
            children: [
              const SizedBox(
                height: 50,
              ),
              Text(
                "Continue to your account",
                style: TextStyle(color: Colors.white, fontSize: 17),
              ),
              const SizedBox(
                height: 100,
              ),
              Expanded(
                child: Container(
                    padding: const EdgeInsets.all(30.0),
                    width: MediaQuery.of(context).size.width,
                    height: MediaQuery.of(context).size.height,
                    decoration: BoxDecoration(
                      color: Colors.white,
                      borderRadius: const BorderRadius.only(
                          topLeft: Radius.circular(20),
                          topRight: Radius.circular(20)),
                    ),
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                      children: [
                        Column(
                          children: [
                            CustomTextField(
                              _emailController,
                              hint: 'Email',
                              password: false,
                            ),
                            const SizedBox(
                              height: 20,
                            ),
                            CustomTextField(
                              _passwordController,
                              hint: 'Password',
                              obscure: true,
                            ),
                            const SizedBox(
                              height: 8,
                            ),
                            GestureDetector(
                              onTap: () {
                                //Forgot Password Page
                              },
                              child: Container(
                                  alignment: Alignment.centerRight,
                                  child:
                                      const Text("Can't remember password?")),
                            ),
                            const SizedBox(
                              height: 20,
                            ),
                          ],
                        ),
                        GestureDetector(
                          onTap: () {
                            print(_emailController.text);
                            print(_passwordController.text);
                            //Validate User Inputs
                          },
                          child: Container(
                            padding: const EdgeInsets.all(15.0),
                            width: MediaQuery.of(context).size.width,
                            decoration: BoxDecoration(
                              color: Colors.purple,
                              borderRadius: BorderRadius.circular(10),
                            ),
                            child: Text(
                              "Login",
                              style: TextStyle(color: Colors.white),
                              textAlign: TextAlign.center,
                            ),
                          ),
                        ),
                        GestureDetector(
                          onTap: () {
                            //Navigate to Register Page
                          },
                          child: Text(
                            "Want to join?",
                            style: TextStyle(fontSize: 17),
                          ),
                        ),
                      ],
                    )),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Getting Started

This project is a starting point for a Dart package, a library module containing code that can be shared easily across multiple Flutter or Dart projects.

For help getting started with Flutter, view our online documentation, which offers tutorials, samples, guidance on mobile development, and a full API reference.

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add flutter_text_form_field

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  flutter_text_form_field: ^1.0.3

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:flutter_text_form_field/flutter_text_form_field.dart'; 

Download Details:

Author: Destiny-Ed

Source Code: https://github.com/Destiny-Ed/flutter_text_form_field

#flutter #text 

A New Flutter Package That Provide Already Made Text form Field
Royce  Reinger

Royce Reinger

1659141300

Gabbler: Gab-bler (noun) - Rapid, Unintelligible Talk

Gabbler

Gabbler is a Ruby library that generates pseudo-random phrases. Any coherent text file with adequate number of sentences could serve as Gabbler's training set. Once trained, Gabbler produces pseudo-random sentences based on the original text.

Installation

# Installing as Ruby gem
$ gem install gabbler

# Cloning the repository
$ git clone git://github.com/michaeldv/gabbler.git

Usage Example

$ cat > holmes.rb
require "gabbler"                         # Require the gem.
gabbler = Gabbler.new                     # Create new Gabbler instance.
story = File.read("./sample/holmes.txt")  # Read first chapter of 'A study in Scarlet'.
gabbler.learn(story)                      # Make Gabbler learn about Sherlock Holmes.
10.times { puts gabbler.sentence }        # Generate ten pseudo-rando sentences.
gabbler.unlearn!                          # Forget Sherlock Holmes.
gabbler.learn(story.reverse)              # Teach Gabbler about semloH kcolrehS.
puts gabbler.sentence                     # .dezama eB
^D
$ ruby holmes.rb
This is very piquant.
You perceive that the resulting mixture has the appearance of pure water.
How on earth did you know that?
If you like, we shall drive round together after luncheon.
Now we have the Sherlock Holmes' test, and there will no longer be any difficulty.    
I followed, however, with many other officers who were in the enemy's country.    
This was a lofty chamber, lined and littered with countless bottles.
My companion smiled an enigmatical smile.
Did you never ask him what he was going in for?
So is the microscopic examination for blood corpuscles.    
senil esoht no repap a trats thgim uoY.

Running Specs

$ gem install rspec           # RSpec 2.x is the requirement.
$ rake spec                   # Run the entire spec suite.

Note on Patches/Pull Requests

  • Fork the project on Github.
  • Make your feature addition or bug fix.
  • Add specs for it, making sure $ rake spec is all green.
  • Commit, do not mess with Rakefile, version, or history.
  • Send me a pull request.

Author: Michaeldv
Source Code: https://github.com/michaeldv/gabbler 
License: View license

#ruby #text 

Gabbler: Gab-bler (noun) - Rapid, Unintelligible Talk
Royce  Reinger

Royce Reinger

1658992440

Gibber: Nonsensical Latin Text Transformation

Gibber

Gibber replaces text with nonsensical latin with a maximum size difference of +/- 30%.

Useful for testing the effects of localization on UI.

Installation

Add this line to your application's Gemfile:

gem 'gibber'

And then execute:

$ bundle

Or install it yourself as:

$ gem install gibber

Usage

gibber = Gibber.new
gibber.replace("I have a passion for crooked bananas")
# => A arcu a fringilla nisi tempus venenatis (maybe)
# Roughly translates to 'From the bow, poisoned from the ecological, unless time'

Gibber preserves any non wordy characters to give your text that texty feel.

Contributing

  1. Fork it ( https://github.com/[my-github-username]/latin_replace/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

Author: Timonv
Source Code: https://github.com/timonv/gibber 
License: MIT license

#ruby #text 

Gibber: Nonsensical Latin Text Transformation
Monty  Boehm

Monty Boehm

1658991600

Textanalysis.jl: Julia Package for Text Analysis

TextAnalysis

A Julia package for working with text.  

Introduction

TextAnalysis provides support for standard tools and models for working with textual data and natural languages in the Julia language.

Features

  • Container type for Document and Corpus
  • DocumentTermMatrix and TF/IDF
  • LSA/LDA
  • Vocabulary and statistical Language Model
  • Co-occurance matrix
  • NaiveBayes classifier
  • ROUGE evaluation metrics

This package also incorporates features from the Languages and WordTokenizers packages within the JuliaText ecosystem.

Installation

The TextAnalysis package can be installed using Julia's package manager:

Pkg.add("TextAnalysis")

Loading

In all of the examples that follow, we'll assume that you have the TextAnalysis package fully loaded. This means that we think you've implicitly typed

using TextAnalysis

before every snippet of code.

TextModels

The TextModels package enhances this library with the additon of practical neural network based models. Some of that code used to live in this package, but was moved to simplify installation and dependencies.

Contributing and Reporting Bugs

Contributions, in the form of bug-reports, pull requests, additional documentation are encouraged. They can be made to the Github repository.

All contributions and communications should abide by the Julia Community Standards.

Support

Feel free to ask for help on the Julia Discourse forum, or in the #natural-language channel on julia-slack. (Which you can join here). You can also raise issues in this repository to request new features and/or improvements to the documentation and codebase.

Author: JuliaText
Source Code: https://github.com/JuliaText/TextAnalysis.jl 
License: View license

#julia #text 

Textanalysis.jl: Julia Package for Text Analysis
Monty  Boehm

Monty Boehm

1658987700

Text.jl: Numerous tools for Text Processing

TEXT: Numerous tools for text processing

This package is a julia implementation of:

  1. Text classification based on BoW models (e.g. topic/langauge id)
  2. Language ID (training and processing) based on word and character n-grams
  3. Lewis's SMART stop list for English
  4. tfidf/tfllr text feature normalization
  5. ngram feature extractors

Prerequistes

  • Stage - Needed for logging and memoization (Note: requires manual install)
  • Ollam - online learning modules (Note: requires manual install)
  • Devectorize - macro-based devectorization
  • DataStructures - for DefaultDict
  • Devectorize
  • GZip
  • Iterators - for iterator helper functions

Install

This is an experimental package which is not currently registered in the julia central repository. You can install via:

Pkg.clone("https://github.com/saltpork/Stage.jl")
Pkg.clone("https://github.com/mit-nlp/Ollam.jl")
Pkg.clone("https://github.com/mit-nlp/Text.jl")

Usage

See test/runtests.jl for detailed usage.

Author: Mit-nlp
Source Code: https://github.com/mit-nlp/Text.jl 
License: Apache-2.0 license

#julia #text #nlp 

Text.jl: Numerous tools for Text Processing
Royce  Reinger

Royce Reinger

1658977500

A Ruby Library for Generating Text with Recursive Template Grammars

Calyx

Calyx provides a simple API for generating text with declarative recursive grammars.

Install

Command Line

gem install calyx

Gemfile

gem 'calyx'

Examples

The best way to get started quickly is to install the gem and run the examples locally.

Any Gradient

Requires Roda and Rack to be available.

gem install roda

Demonstrates how to use Calyx to construct SVG graphics. Any Gradient generates a rectangle with a linear gradient of random colours.

Run as a web server and preview the output in a browser (http://localhost:9292):

ruby examples/any_gradient.rb

Or generate SVG files via a command line pipe:

ruby examples/any_gradient > gradient1.xml

Tiny Woodland Bot

Requires the Twitter client gem and API access configured for a specific Twitter handle.

gem install twitter

Demonstrates how to use Calyx to make a minimal Twitter bot that periodically posts unique tweets. See @tiny_woodland on Twitter and the writeup here.

TWITTER_CONSUMER_KEY=XXX-XXX
TWITTER_CONSUMER_SECRET=XXX-XXX
TWITTER_ACCESS_TOKEN=XXX-XXX
TWITTER_CONSUMER_SECRET=XXX-XXX
ruby examples/tiny_woodland_bot.rb

Faker

Faker is a popular library for generating fake names and associated sample data like internet addresses, company names and locations.

This example demonstrates how to use Calyx to reproduce the same functionality using custom lists defined in a YAML configuration file.

ruby examples/faker.rb

Usage

Require the library and inherit from Calyx::Grammar to construct a set of rules to generate a text.

require 'calyx'

class HelloWorld < Calyx::Grammar
  start 'Hello world.'
end

To generate the text itself, initialize the object and call the generate method.

hello = HelloWorld.new
hello.generate
# > "Hello world."

Obviously, this hardcoded sentence isn’t very interesting by itself. Possible variations can be added to the text by adding additional rules which provide a named set of text strings. The rule delimiter syntax ({}) can be used to substitute the generated content of other rules.

class HelloWorld < Calyx::Grammar
  start '{greeting} world.'
  greeting 'Hello', 'Hi', 'Hey', 'Yo'
end

Each time #generate runs, it evaluates the tree and randomly selects variations of rules to construct a resulting string.

hello = HelloWorld.new

hello.generate
# > "Hi world."

hello.generate
# > "Hello world."

hello.generate
# > "Yo world."

By convention, the start rule specifies the default starting point for generating the final text. You can start from any other named rule by passing it explicitly to the generate method.

class HelloWorld < Calyx::Grammar
  hello 'Hello world.'
end

hello = HelloWorld.new
hello.generate(:hello)

Block Constructors

As an alternative to subclassing, you can also construct rules unique to an instance by passing a block when initializing the class:

hello = Calyx::Grammar.new do
  start '{greeting} world.'
  greeting 'Hello', 'Hi', 'Hey', 'Yo'
end

hello.generate

Template Expressions

Basic rule substitution uses single curly brackets as delimiters for template expressions:

fruit = Calyx::Grammar.new do
  start '{colour} {fruit}'
  colour 'red', 'green', 'yellow'
  fruit 'apple', 'pear', 'tomato'
end

6.times { fruit.generate }
# => "yellow pear"
# => "red apple"
# => "green tomato"
# => "red pear"
# => "yellow tomato"
# => "green apple"

Nesting and Substitution

Rules are recursive. They can be arbitrarily nested and connected to generate larger and more complex texts.

class HelloWorld < Calyx::Grammar
  start '{greeting} {world_phrase}.'
  greeting 'Hello', 'Hi', 'Hey', 'Yo'
  world_phrase '{happy_adj} world', '{sad_adj} world', 'world'
  happy_adj 'wonderful', 'amazing', 'bright', 'beautiful'
  sad_adj 'cruel', 'miserable'
end

Nesting and hierarchy can be manipulated to balance consistency with novelty. The exact same word atoms can be combined in a variety of ways to produce strikingly different resulting texts.

module HelloWorld
  class Sentiment < Calyx::Grammar
    start '{happy_phrase}', '{sad_phrase}'
    happy_phrase '{happy_greeting} {happy_adj} world.'
    happy_greeting 'Hello', 'Hi', 'Hey', 'Yo'
    happy_adj 'wonderful', 'amazing', 'bright', 'beautiful'
    sad_phrase '{sad_greeting} {sad_adj} world.'
    sad_greeting 'Goodbye', 'So long', 'Farewell'
    sad_adj 'cruel', 'miserable'
  end

  class Mixed < Calyx::Grammar
    start '{greeting} {adj} world.'
    greeting 'Hello', 'Hi', 'Hey', 'Yo', 'Goodbye', 'So long', 'Farewell'
    adj 'wonderful', 'amazing', 'bright', 'beautiful', 'cruel', 'miserable'
  end
end

Random Sampling

By default, the outcomes of generated rules are selected with Ruby’s built-in pseudorandom number generator (as seen in methods like Kernel.rand and Array.sample). To seed the random number generator, pass in an integer seed value as the first argument to the constructor:

grammar = Calyx::Grammar.new(seed: 12345) do
  # rules...
end

Alternatively, you can pass a preconfigured instance of Ruby’s stdlib Random class:

random = Random.new(12345)

grammar = Calyx::Grammar.new(rng: random) do
  # rules...
end

When a random seed isn’t supplied, Time.new.to_i is used as the default seed, which makes each run of the generator relatively unique.

Weighted Choices

Choices can be weighted so that some rules have a greater probability of expanding than others.

Weights are defined by passing a hash instead of a list of rules where the keys are strings or symbols representing the grammar rules and the values are weights.

Weights can be represented as floats, integers or ranges.

  • Floats must be in the interval 0..1 and the given weights for a production must sum to 1.
  • Ranges must be contiguous and cover the entire interval from 1 to the maximum value of the largest range.
  • Integers (Fixnums) will produce a distribution based on the sum of all given numbers, with each number being a fraction of that sum.

The following definitions produce an equivalent weighting of choices:

Calyx::Grammar.new do
  start 'heads' => 1, 'tails' => 1
end

Calyx::Grammar.new do
  start 'heads' => 0.5, 'tails' => 0.5
end

Calyx::Grammar.new do
  start 'heads' => 1..5, 'tails' => 6..10
end

Calyx::Grammar.new do
  start 'heads' => 50, 'tails' => 50
end

There’s a lot of interesting things you can do with this. For example, you can model the triangular distribution produced by rolling 2d6:

Calyx::Grammar.new do
  start(
    '2' => 1,
    '3' => 2,
    '4' => 3,
    '5' => 4,
    '6' => 5,
    '7' => 6,
    '8' => 5,
    '9' => 4,
    '10' => 3,
    '11' => 2,
    '12' => 1
  )
end

Or reproduce Gary Gygax’s famous generation table from the original Dungeon Master’s Guide (page 171):

Calyx::Grammar.new do
  start(
    :empty => 0.6,
    :monster => 0.1,
    :monster_treasure => 0.15,
    :special => 0.05,
    :trick_trap => 0.05,
    :treasure => 0.05
  )
  empty 'Empty'
  monster 'Monster Only'
  monster_treasure 'Monster and Treasure'
  special 'Special'
  trick_trap 'Trick/Trap.'
  treasure 'Treasure'
end

String Modifiers

Dot-notation is supported in template expressions, allowing you to call any available method on the String object returned from a rule. Formatting methods can be chained arbitrarily and will execute in the same way as they would in native Ruby code.

greeting = Calyx::Grammar.new do
  start '{hello.capitalize} there.', 'Why, {hello} there.'
  hello 'hello', 'hi'
end

4.times { greeting.generate }
# => "Hello there."
# => "Hi there."
# => "Why, hello there."
# => "Why, hi there."

You can also extend the grammar with custom modifiers that provide useful formatting functions.

Filters

Filters accept an input string and return the transformed output:

greeting = Calyx::Grammar.new do
  filter :shoutycaps do |input|
    input.upcase
  end

  start '{hello.shoutycaps} there.', 'Why, {hello.shoutycaps} there.'
  hello 'hello', 'hi'
end

4.times { greeting.generate }
# => "HELLO there."
# => "HI there."
# => "Why, HELLO there."
# => "Why, HI there."

Mappings

The mapping shortcut allows you to specify a map of regex patterns pointing to their resulting substitution strings:

green_bottle = Calyx::Grammar.new do
  mapping :pluralize, /(.+)/ => '\\1s'
  start 'One green {bottle}.', 'Two green {bottle.pluralize}.'
  bottle 'bottle'
end

2.times { green_bottle.generate }
# => "One green bottle."
# => "Two green bottles."

Modifier Mixins

In order to use more intricate rewriting and formatting methods in a modifier chain, you can add methods to a module and embed it in a grammar using the modifier classmethod.

Modifier methods accept a single argument representing the input string from the previous step in the expression chain and must return a string, representing the modified output.

module FullStop
  def full_stop(input)
    input << '.'
  end
end

hello = Calyx::Grammar.new do
  modifier FullStop
  start '{hello.capitalize.full_stop}'
  hello 'hello'
end

hello.generate
# => "Hello."

To share custom modifiers across multiple grammars, you can include the module in Calyx::Modifiers. This will make the methods available to all subsequent instances:

module FullStop
  def full_stop(input)
    input << '.'
  end
end

class Calyx::Modifiers
  include FullStop
end

Monkeypatching String

Alternatively, you can combine methods from existing Gems that monkeypatch String:

require 'indefinite_article'

module FullStop
  def full_stop
    self << '.'
  end
end

class String
  include FullStop
end

noun_articles = Calyx::Grammar.new do
  start '{fruit.with_indefinite_article.capitalize.full_stop}'
  fruit 'apple', 'orange', 'banana', 'pear'
end

4.times { noun_articles.generate }
# => "An apple."
# => "An orange."
# => "A banana."
# => "A pear."

Memoized Rules

Rule expansions can be ‘memoized’ so that multiple references to the same rule return the same value. This is useful for picking a noun from a list and reusing it in multiple places within a text.

The @ sigil is used to mark memoized rules. This evaluates the rule and stores it in memory the first time it’s referenced. All subsequent references to the memoized rule use the same stored value.

# Without memoization
grammar = Calyx::Grammar.new do
  start '{name} <{name.downcase}>'
  name 'Daenerys', 'Tyrion', 'Jon'
end

3.times { grammar.generate }
# => Daenerys <jon>
# => Tyrion <daenerys>
# => Jon <tyrion>

# With memoization
grammar = Calyx::Grammar.new do
  start '{@name} <{@name.downcase}>'
  name 'Daenerys', 'Tyrion', 'Jon'
end

3.times { grammar.generate }
# => Tyrion <tyrion>
# => Daenerys <daenerys>
# => Jon <jon>

Note that the memoization symbol can only be used on the right hand side of a production rule.

Unique Rules

Rule expansions can be marked as ‘unique’, meaning that multiple references to the same rule always return a different value. This is useful for situations where the same result appearing twice would appear awkward and messy.

Unique rules are marked by the $ sigil.

grammar = Calyx::Grammar.new do
  start "{$medal}, {$medal}, {$medal}"
  medal 'Gold', 'Silver', 'Bronze'
end

grammar.generate
# => Silver, Bronze, Gold

Dynamically Constructing Rules

Template expansions can be dynamically constructed at runtime by passing a context map of rules to the #generate method:

class AppGreeting < Calyx::Grammar
  start 'Hi {username}!', 'Welcome back {username}...', 'Hola {username}'
end

context = {
  username: UserModel.username
}

greeting = AppGreeting.new
greeting.generate(context)

External File Formats

In addition to defining grammars in pure Ruby, you can load them from external JSON and YAML files:

hello = Calyx::Grammar.load('hello.yml')
hello.generate

The format requires a flat map with keys representing the left-hand side named symbols and the values representing the right hand side substitution rules.

In JSON:

{
  "start": "{greeting} world.",
  "greeting": ["Hello", "Hi", "Hey", "Yo"]
}

In YAML:

---
start: "{greeting} world."
greeting:
  - Hello
  - Hi
  - Hey
  - Yo

Accessing the Raw Generated Tree

Calling #evaluate on the grammar instance will give you access to the raw generated tree structure before it gets flattened into a string.

The tree is encoded as an array of nested arrays, with the leading symbols labeling the choices and rules selected, and the trailing terminal leaves encoding string values.

This may not make a lot of sense unless you’re familiar with the concept of s-expressions. It’s a fairly speculative feature at this stage, but it leads to some interesting possibilities.

grammar = Calyx::Grammar.new do
  start 'Riddle me ree.'
end

grammar.evaluate
# => [:start, [:choice, [:concat, [[:atom, "Riddle me ree."]]]]]

Roadmap

Rough plan for stabilising the API and features for a 1.0 release.

VersionFeatures planned
0.6block constructor
0.7support for template context map passed to generate
0.8method missing metaclass API
0.9return grammar tree from #evaluate, with flattened string from #generate being separate
0.10inject custom string functions for parameterised rules, transforms and mappings
0.11support YAML format (and JSON?)
0.12API documentation
0.13Support for unique rules
0.14Support for Ruby 2.4
0.15Options config and ‘strict mode’ error handling
0.16Improve representation of weighted probability selection
0.17Return result object from #generate calls

Credits

Author & Maintainer

Contributors

Author: Maetl
Source Code: https://github.com/maetl/calyx 
License: MIT license

#ruby #text 

A Ruby Library for Generating Text with Recursive Template Grammars