README.md in search_lingo-1.0.1 vs README.md in search_lingo-1.0.2

- old
+ new

@@ -1,6 +1,6 @@ -# [![Gem Version](https://badge.fury.io/rb/search_lingo.svg)](http://badge.fury.io/rb/search_lingo) +# [![Gem Version](https://badge.fury.io/rb/search_lingo.svg)](http://badge.fury.io/rb/search_lingo) [![Build Status](https://travis-ci.org/jparker/search_lingo.svg?branch=master)](https://travis-ci.org/jparker/search_lingo) # SearchLingo SearchLingo is a framework for defining simple, user-friendly query languages and translating them into their underlying queries. @@ -31,11 +31,12 @@ $ gem install search_lingo ## Usage -Here is a simple example. +Concrete examples of how to use this gem are provided in `examples/` and +`test/examples/`, but here is a simple example. ```ruby class Task < ActiveRecord::Base end @@ -114,32 +115,30 @@ Create a class which inherits from `SearchLingo::AbstractSearch`. Provide an implementation of `#default_parse` in that class. Register parsers for specific types of search tokens using the parser class method. Instantiate your search class by passing in the query string and the scope on -which to perform the search. Use the `#results` method to compile the search -and return the results. +which to perform the search. Use the `#results` method to compile and execute +the search and return the results. -Take a look at the examples/ directory for more concrete examples. - ## How It Works A search is instantiated with a query string and a search scope (commonly an ActiveRecord model). The search breaks the query string down into a series of tokens, and each token is processed by a declared series of parsers. If a parser succeeds, processing immediately advances to the next token. If none of the declared parsers succeeds, and the token is compound — that is, the token -is composed of an operator and a term (e.g., `foo: bar`), the token is +is composed of a modifier and a term (e.g., `foo: bar`), the token is simplified and then processed by the declared parsers again. If the second pass also fails, then the (now simplified) token falls through to the `#default_parse` method defined by the search class. This method should be implemented in such a way that it always "succeeds" — always returning a Symbol or an Array that can be splatted and sent to the search scope. ## Search Classes -Search classes should inherit from `SearchLogic::AbstractSearch`, and they must +Search classes should inherit from `SearchLingo::AbstractSearch`, and they must provide their own implementation of `#default_parse`. Optionally, a search class may also use the parse class method to add specialized parsers for handling tokens that match specific patterns. As each token is processed, the search class will first run through the specialized parsers. If none of them succeed, it will fall back on the `#default_parse` method. See the section @@ -147,45 +146,45 @@ structured. ## Tokenization Queries are comprised of zero or more tokens separated by white space. A token -has a term and an optional operator. (A simple token has no operator; a +has a term and an optional modifier. (A simple token has no modifier; a compound token does.) A term can be a single word or multiple words joined by spaces and contained within double quotes. For example `foo` and `"foo bar -baz"` are both single terms. An operator is one or more alphanumeric characters +baz"` are both single terms. A modifier is one or more alphanumeric characters followed by a colon and zero or more spaces. QUERY := TOKEN* - TOKEN := (OPERATOR ':' [[:space:]]*)? TERM - OPERATOR := [[:alnum:]]+ + TOKEN := (MODIFIER ':' [[:space:]]*)? TERM + MODIFIER := [[:alnum:]]+ TERM := '"' [^"]* '"' | [[:graph:]]+ The following are all examples of tokens: * `foo` * `"foo bar"` * `foo: bar` * `foo: "bar baz"` (If you need a term to equal something that might otherwise be interpreted as -an operator, you can enclose the term in double quotes, e.g., while `foo: bar` +a modifier, you can enclose the term in double quotes, e.g., while `foo: bar` would be interpreted a single compound token, `"foo:" bar` would be treated as two distinct simple tokens, and `"foo: bar"` would be treated as a single simple token.) -Tokens are passed to parsers as instances of the SearchLingo::Token class. -SearchLingo::Token provides `#operator` and `#term` methods, but delegates all -other behavior to the String class. Consequently, when writing parsers, you -have the option of either interacting with examining the operator and term +Tokens are passed to parsers as instances of the `SearchLingo::Token` class. +`SearchLingo::Token` provides `#modifier` and `#term` methods, but delegates +all other behavior to the String class. Consequently, when writing parsers, you +have the option of either interacting with examining the modifier and term individually or treating the entire token as a String and processing it yourself. The following would produce identical results: ```ruby token = SearchLingo::Token.new('foo: "bar baz"') -if token.operator == 'foo' then token.term end # => 'bar baz' +if token.modifier == 'foo' then token.term end # => 'bar baz' token.match(/\Afoo:\s*"?(.+?)"?\z/) { |m| m[1] } # => 'bar baz' ``` (Note that `#term` takes care of stripping away quotes from the term.) @@ -233,13 +232,13 @@ classes: ```ruby module Parsers class IdParser - def initialize(table, operator = nil) + def initialize(table, modifier = nil) @table = table - @prefix = /#{operator}:\s*/ if operator + @prefix = /#{modifier}:\s*/ if modifier end def call(token) token.match /\A#{@prefix}([[:digit:]]+)\z/ do |m| [:where, { @table => { id: m[1] } }] @@ -274,11 +273,15 @@ June 2015, respectively, but `6/11` will be parsed as 11 June *2014*.) Additionally, there are parsers for handling closed date ranges (e.g., `1/1/15-6/30/15`) as well as open-ended date ranges (e.g., `1/1/15-` and `12/31/15`). Look at the files in `lib/search_lingo/parsers` for more details. -As implemented, the date parsers are US-centric. I would like to work on making -them more flexible when time permits. +The date parser are specifically designed to work with US-formatted dates. Time +permitting, I will work on making them more flexible. As implemented they are +also ActiveRecord-centric; this also needs to be reexamined reexamined, either +by finding a more agnostic implementation or renaming the parser classes to +indicate they are ActiveRecord-only implementations. (If going the latter +route, a Sequel-specific implementation should also be provided.) ## Development After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.