Skip to content

Commit

Permalink
Merge branch 'feature/v2'
Browse files Browse the repository at this point in the history
  • Loading branch information
caleb531 committed Mar 2, 2015
2 parents 4733bda + 8c99870 commit c60d073
Show file tree
Hide file tree
Showing 49 changed files with 2,370 additions and 883 deletions.
8 changes: 5 additions & 3 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ exclude_lines =

# Only check coverage for source files
include =
yv_suggest/google.py
yv_suggest/open.py
yv_suggest/search.py
yv_suggest/shared.py
yv_suggest/filter_refs.py
yv_suggest/filter_prefs.py
yv_suggest/view_ref.py
yv_suggest/search_ref.py
yv_suggest/set_pref.py
80 changes: 34 additions & 46 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,68 +6,56 @@
YouVersion Suggest is an Alfred workflow which allows you to search the online
[YouVersion](https://www.youversion.com/) bible quickly and conveniently.

![YouVersion Suggest in action](screenshots/chapters.png)
![YouVersion Suggest in action](screenshot.png)

## Usage

Type the `yv` keyword, followed by a space and a phrase representing the bible
reference you wish to find. The phrase can be part of a book name, chapter,
verse, or range of verses. You may also include an option version (translation)
at the end of your query. As you type, YouVersion Suggest will display a list of
suggestions matching your query.
Type the `yv` keyword into Alfred, followed by a space and a phrase representing
the bible reference you wish to find. The phrase can be part of a book name,
chapter, verse, or range of verses. You may also include an optional version
(translation) at the end of your query. As you type, YouVersion Suggest will
display a list of suggestions matching your query.

Choosing a result will open the selected reference on the YouVersion website.
Choosing a result while holding down the *ctrl* key will open a Google
search for the selected reference.

### Query Examples
### Example queries

* `luke` => Luke
* `eph 3` => Ephesians 3
* `1t3e` => 1 Thessalonians 3 (ESV), 1 Timothy 3 (ESV)
* `mat 6:34 nlt` => Matthew 6:34 (NLT)
* `1 co 13.4-7` => 1 Corinthians 13:4-7
* `yv luke` => Luke
* `yv eph 3` => Ephesians 3
* `yv 1t3e` => 1 Thessalonians 3 (ESV), 1 Timothy 3 (ESV)
* `yv mat 6:34 nlt` => Matthew 6:34 (NLT)
* `yv 1 co 13.4-7` => 1 Corinthians 13:4-7
* `yv relevations 7` => Revelation 7

### Supported versions
### Setting your preferred language

#### English
YouVersion Suggest allows you to change the languages used for Bible references
and versions. To do so, type `yvset language` into Alfred, and the list of
supported languages will then appear. You may then choose another language as
your preferred language.

AMP, ASV, BOOKS, CEB, CEV, CEV, CEVUK, CPDV, DARBY, DRA, ESV, ERV, GNB, GNBDC, GNBDK, GNT, GNTD, GWT, HCSB, ISR98, KJV, LEB, MSG, NIV, NIVUK, NLT, NET, NKJV, NCV, NASB, NABRE, NIRV, OJB, RV1885, TLV, WEB
Currently, YouVersion Suggest supports the following languages:

YouVersion Suggest defaults to NIV, however it will always remember the last version you used to look up a reference.
* English
* Spanish
* Dutch

## Testing
If you would like support added for another language, please [submit an issue on
GitHub](https://github.com/caleb531/youversion-suggest/issues).

### Requirements for running tests
### Setting your preferred version

Running these unit tests requires Python 2.7, as well as the following packages
to be installed:
You may also set your preferred version (translation) used for Bible references
(where you have not explicitly specified the version in the query). To do so,
type `yvset version` into Alfred, and the list of supported versions (for the
currently-set language) will appear.

* nose
* coverage
* pep8
To select a version from the list of versions more quickly, you may optionally
type a query after the initial query to filter the list of versions.

If you do not have these packages installed already, you can install them via
`pip`:
#### Example queries

```
sudo pip install nose coverage pep8
```

### Running tests

To run the included unit tests, run the `nosetests` command within the project
directory.

```
nosetests
```

### Viewing test coverage

To view the test coverage report, run `nosetests` with the `--with-coverage` and
`--cover-erase` flags.

```
nosetests --with-coverage --cover-erase
```
* `yvset version esv`
* `yvset version a`
Binary file modified YouVersion Suggest.alfredworkflow
Binary file not shown.
Binary file added screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed screenshots/books.png
Binary file not shown.
Binary file removed screenshots/chapters.png
Binary file not shown.
Binary file removed screenshots/verse-ranges.png
Binary file not shown.
Binary file removed screenshots/verses.png
Binary file not shown.
18 changes: 18 additions & 0 deletions tests/context_managers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from contextlib import contextmanager
from io import BytesIO
import sys


@contextmanager
def redirect_stdout():
"""temporarily redirect stdout to new output stream"""
original_stdout = sys.stdout
out = BytesIO()
try:
sys.stdout = out
yield out
finally:
sys.stdout = original_stdout
43 changes: 43 additions & 0 deletions tests/test_compliance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import unicode_literals
import nose.tools as nose
import glob
import json
import pep8
import jsonschema


def test_pep8():
files = glob.iglob('*/*.py')
for file in files:
test_pep8.__doc__ = '{} should comply with pep8'.format(file)
style_guide = pep8.StyleGuide(quiet=True)
total_errors = style_guide.input_file(file)
msg = '{} is not pep8-compliant'.format(file)
yield nose.assert_equal, total_errors, 0, msg


def test_json():
schemas = {
'schema-languages': 'yv_suggest/data/languages.json',
'schema-defaults': 'yv_suggest/data/defaults.json',
'schema-chapters': 'yv_suggest/data/bible/chapters.json',
'schema-bible': 'yv_suggest/data/bible/language-*.json'
}
for schema_name, data_path_pattern in schemas.iteritems():
schema_path = 'yv_suggest/data/schema/{}.json'.format(schema_name)
with open(schema_path) as schema_file:
schema = json.load(schema_file)
data_paths = glob.iglob(data_path_pattern)
for data_path in data_paths:
test_json.__doc__ = '{} should be schema-compliant'.format(
data_path)
with open(data_path) as data_file:
data = json.load(data_file)
try:
validator = jsonschema.validate(data, schema)
yield nose.assert_is_none, validator
except jsonschema.exceptions.ValidationError as error:
assert False, error
71 changes: 71 additions & 0 deletions tests/test_filter_prefs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import unicode_literals
import nose.tools as nose
import yv_suggest.filter_prefs as yvs
from xml.etree import ElementTree as ET
from context_managers import redirect_stdout


def test_show_languages():
"""should show all languages if no value is given"""
results = yvs.get_result_list('language', prefs={})
nose.assert_not_equal(len(results), 0)


def test_filter_languages():
"""should filter available languages if value is given"""
results = yvs.get_result_list('language en', prefs={})
nose.assert_equal(len(results), 1)
nose.assert_equal(results[0]['title'], 'English')
nose.assert_equal(results[0]['arg'], 'language:en')


def test_show_versions():
"""should show all versions if no value is given"""
results = yvs.get_result_list('version', prefs={})
nose.assert_not_equal(len(results), 0)


def test_filter_versions():
"""should filter available versions if value is given"""
results = yvs.get_result_list('version ni', prefs={})
nose.assert_equal(len(results), 3)
nose.assert_equal(results[0]['title'], 'NIRV')
nose.assert_equal(results[0]['arg'], 'version:110')


def test_nonexistent():
"""should not match nonexistent preferences"""
results = yvs.get_result_list('xyz', prefs={})
nose.assert_equal(len(results), 0)


def test_invalid():
"""should not match nonexistent preferences"""
results = yvs.get_result_list('!@#', prefs={})
nose.assert_equal(len(results), 0)


def test_main_output():
"""should output pref result list XML"""
query_str = 'language'
with redirect_stdout() as out:
yvs.main(query_str, prefs={})
output = out.getvalue().strip()
results = yvs.get_result_list(query_str, prefs={})
xml = yvs.shared.get_result_list_xml(results).strip()
nose.assert_equal(output, xml)


def test_null_result():
"""should output "No Results" XML item for empty pref result lists"""
query_str = 'xyz'
with redirect_stdout() as out:
yvs.main(query_str, prefs={})
xml = out.getvalue().strip()
root = ET.fromstring(xml)
item = root.find('item')
nose.assert_is_not_none(item, '<item> element is missing')
nose.assert_equal(item.get('valid'), 'no')
37 changes: 23 additions & 14 deletions tests/test_search_book.py → tests/test_filter_refs_book.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,32 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import unicode_literals
import nose.tools as nose
import yv_suggest.search as yvs
import yv_suggest.filter_refs as yvs


def test_partial():
"""should match books by partial name"""
results = yvs.get_result_list('luk')
results = yvs.get_result_list('luk', prefs={})
nose.assert_equal(len(results), 1)
nose.assert_equal(results[0]['title'], 'Luke 1 (NIV)')


def test_case():
"""should match books irrespective of case"""
query_str = 'Matthew'
results = yvs.get_result_list(query_str)
results_lower = yvs.get_result_list(query_str.lower())
results_upper = yvs.get_result_list(query_str.upper())
results = yvs.get_result_list(query_str, prefs={})
results_lower = yvs.get_result_list(query_str.lower(), prefs={})
results_upper = yvs.get_result_list(query_str.upper(), prefs={})
nose.assert_equal(len(results), 1)
nose.assert_list_equal(results_lower, results)
nose.assert_list_equal(results_upper, results)


def test_partial_ambiguous():
"""should match books by ambiguous partial name"""
results = yvs.get_result_list('r')
results = yvs.get_result_list('r', prefs={})
nose.assert_equal(len(results), 3)
nose.assert_equal(results[0]['title'], 'Ruth 1 (NIV)')
nose.assert_equal(results[1]['title'], 'Romans 1 (NIV)')
Expand All @@ -33,28 +35,28 @@ def test_partial_ambiguous():

def test_multiple_words():
"""should match books with names comprised of multiple words"""
results = yvs.get_result_list('song of songs')
results = yvs.get_result_list('song of songs', prefs={})
nose.assert_equal(len(results), 1)
nose.assert_equal(results[0]['title'], 'Song of Songs 1 (NIV)')
nose.assert_equal(results[0]['title'], 'Song of Solomon 1 (NIV)')


def test_numbered_partial():
"""should match numbered books by partial numbered name"""
results = yvs.get_result_list('1 cor')
results = yvs.get_result_list('1 cor', prefs={})
nose.assert_equal(len(results), 1)
nose.assert_equal(results[0]['title'], '1 Corinthians 1 (NIV)')


def test_numbered_whitespace():
"""should match numbered books irrespective of extra whitespace"""
results = yvs.get_result_list('1 cor')
results = yvs.get_result_list('1 cor', prefs={})
nose.assert_equal(len(results), 1)
nose.assert_equal(results[0]['title'], '1 Corinthians 1 (NIV)')


def test_nonnumbered_partial():
"""should match numbered books by partial non-numbered name"""
results = yvs.get_result_list('john')
results = yvs.get_result_list('john', prefs={})
nose.assert_equal(len(results), 4)
nose.assert_equal(results[0]['title'], 'John 1 (NIV)')
nose.assert_equal(results[1]['title'], '1 John 1 (NIV)')
Expand All @@ -64,11 +66,18 @@ def test_nonnumbered_partial():

def test_id():
"""should use correct ID for books"""
results = yvs.get_result_list('philippians')
nose.assert_equal(results[0]['uid'], 'niv/php.1')
results = yvs.get_result_list('philippians', prefs={})
nose.assert_equal(results[0]['uid'], 'yvs-111/php.1')


def test_closest_match():
"""should try to find closest match for nonexistent books"""
results = yvs.get_result_list('relevations', prefs={})
nose.assert_equal(len(results), 1)
nose.assert_equal(results[0]['title'], 'Revelation 1 (NIV)')


def test_nonexistent():
"""should not match nonexistent books"""
results = yvs.get_result_list('jesus')
results = yvs.get_result_list('xyz', prefs={})
nose.assert_equal(len(results), 0)
Original file line number Diff line number Diff line change
@@ -1,37 +1,39 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import unicode_literals
import nose.tools as nose
import yv_suggest.search as yvs
import yv_suggest.filter_refs as yvs


def test_basic():
"""should match chapters"""
results = yvs.get_result_list('matthew 5')
results = yvs.get_result_list('matthew 5', prefs={})
nose.assert_equal(len(results), 1)
nose.assert_equal(results[0]['title'], 'Matthew 5 (NIV)')


def test_ambiguous():
"""should match chapters by ambiguous book name"""
results = yvs.get_result_list('a 3')
results = yvs.get_result_list('a 3', prefs={})
nose.assert_equal(len(results), 2)
nose.assert_equal(results[0]['title'], 'Amos 3 (NIV)')
nose.assert_equal(results[1]['title'], 'Acts 3 (NIV)')


def test_id():
"""should use correct ID for chapters"""
results = yvs.get_result_list('luke 4')
nose.assert_equal(results[0]['uid'], 'niv/luk.4')
results = yvs.get_result_list('luke 4', prefs={})
nose.assert_equal(results[0]['uid'], 'yvs-111/luk.4')


def test_nonexistent():
"""should not match nonexistent chapters"""
results = yvs.get_result_list('psalm 160')
results = yvs.get_result_list('psalm 160', prefs={})
nose.assert_equal(len(results), 0)


def test_zero_chapter():
"""should not match chapter zero"""
results = yvs.get_result_list('psalm 0')
results = yvs.get_result_list('psalm 0', prefs={})
nose.assert_equal(len(results), 0)
Loading

0 comments on commit c60d073

Please sign in to comment.