Skip to content

Commit 05ffe8e

Browse files
committed
Merge branch '2.0'
2 parents 82379e8 + 4b58a5d commit 05ffe8e

36 files changed

+1923
-1770
lines changed

CHANGELOG.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# CHANGELOG
2+
3+
## 2.0.0 - 2014-01-11
4+
5+
* Moving to a flattened namespace structure.
6+
* Runtimes are now only PHP callables.
7+
* Fixed an error in the way empty JSON literals are parsed so that they now
8+
return an empty string to match the Python and JavaScript implementations.
9+
* Removed functions from runtimes. Instead there is now a function dispatcher
10+
class, FnDispatcher, that provides function implementations behind a single
11+
dispatch function.
12+
* Removed ExprNode in lieu of just using a PHP callable with bound variables.
13+
* Removed debug methods from runtimes and instead into a new Debugger class.
14+
* Heavily cleaned up function argument validation.
15+
* Slice syntax is now properly validated (i.e., colons are followed by the
16+
appropriate value).
17+
* Lots of code cleanup and performance improvements.
18+
* Added a convenient `JmesPath\search()` function.
19+
* **IMPORTANT**: Relocating the project to https://github.com/jmespath/jmespath.php
20+
21+
## 1.1.1 - 2014-10-08
22+
23+
* Added support for using ArrayAccess and Countable as arrays and objects.
24+
25+
## 1.1.0 - 2014-08-06
26+
27+
* Added the ability to search data returned from json_decode() where JSON
28+
objects are returned as stdClass objects.

CHANGELOG.rst

Lines changed: 0 additions & 14 deletions
This file was deleted.

README.rst

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ using the ``mtdowling/jmespath.php`` package.
2222
]
2323
];
2424
25-
\JmesPath\Env::search($expression, $data);
25+
JmesPath\search($expression, $data);
2626
// Returns: [1, 2, 3]
2727
2828
- `JMESPath documentation <http://jmespath.readthedocs.org/en/latest/>`_
@@ -32,26 +32,26 @@ using the ``mtdowling/jmespath.php`` package.
3232
PHP Usage
3333
=========
3434

35-
The ``JmesPath\Env::search`` function can be used in most cases when using the
35+
The ``JmesPath\search`` function can be used in most cases when using the
3636
library. This function utilizes a JMESPath runtime based on your environment.
3737
The runtime utilized can be configured using environment variables and may at
3838
some point in the future automatically utilize a C extension if available.
3939

4040
.. code-block:: php
4141
42-
$result = \JmesPath\Env::search($expression, $data);
42+
$result = JmesPath\search($expression, $data);
43+
44+
// or, if you require PSR-4 compliance.
45+
$result = JmesPath\Env::search($expression, $data);
4346
4447
Runtimes
4548
--------
4649

4750
jmespath.php utilizes *runtimes*. There are currently two runtimes:
4851
AstRuntime and CompilerRuntime.
4952

50-
AstRuntime is utilized by ``JmesPath\Env::search()`` by default. Depending on
51-
your application, it may be useful to customize the runtime used by
52-
``JmesPath\Env::search()``. You can change the runtime utilized by
53-
``JmesPath\Env::search()`` by calling ``JmesPath\registerRuntime()``, passing in an
54-
instance of ``JmesPath\Runtime\RuntimeInterface``.
53+
AstRuntime is utilized by ``JmesPath\search()`` and ``JmesPath\Env::search()``
54+
by default.
5555

5656
AstRuntime
5757
~~~~~~~~~~
@@ -61,10 +61,16 @@ and interpret the AST using an external tree visitor. AstRuntime provides a
6161
good general approach for interpreting JMESPath expressions that have a low to
6262
moderate level of reuse.
6363

64+
.. code-block:: php
65+
66+
$runtime = new JmesPath\AstRuntime();
67+
$runtime('foo.bar', ['foo' => ['bar' => 'baz']]);
68+
// > 'baz'
69+
6470
CompilerRuntime
6571
~~~~~~~~~~~~~~~
6672

67-
``JmesPath\Runtime\CompilerRuntime`` provides the most performance for
73+
``JmesPath\CompilerRuntime`` provides the most performance for
6874
applications that have a moderate to high level of reuse of JMESPath
6975
expressions. The CompilerRuntime will walk a JMESPath AST and emit PHP source
7076
code, resulting in anywhere from 7x to 60x speed improvements.
@@ -80,10 +86,17 @@ Use the CompilerRuntime if you know that you will be executing JMESPath
8086
expressions more than once or if you can pre-compile JMESPath expressions
8187
before executing them (for example, server-side applications).
8288

89+
.. code-block:: php
90+
91+
// Note: The cache directory argument is optional.
92+
$runtime = new JmesPath\CompilerRuntime('/path/to/compile/folder');
93+
$runtime('foo.bar', ['foo' => ['bar' => 'baz']]);
94+
// > 'baz'
95+
8396
Environment Variables
8497
^^^^^^^^^^^^^^^^^^^^^
8598

86-
You can utilize the CompilerRuntime in ``JmesPath\Env::search()`` by setting
99+
You can utilize the CompilerRuntime in ``JmesPath\search()`` by setting
87100
the ``JP_PHP_COMPILE`` environment variable to "on" or to a directory
88101
on disk used to store cached expressions.
89102

bin/jp.php

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
#!/usr/bin/env php
22
<?php
3-
require 'vendor/autoload.php';
3+
require __DIR__ . '/../vendor/autoload.php';
4+
5+
use JmesPath\Env;
6+
use JmesPath\DebugRuntime;
47

58
$description = <<<EOT
69
Runs a JMESPath expression on the provided input or a test case.
@@ -13,10 +16,8 @@
1316
1417
EOT;
1518

16-
// Parse the provided arguments
17-
$args = array();
19+
$args = [];
1820
$currentKey = null;
19-
2021
for ($i = 1, $total = count($argv); $i < $total; $i++) {
2122
if ($i % 2) {
2223
if (substr($argv[$i], 0, 2) == '--') {
@@ -31,21 +32,17 @@
3132
}
3233

3334
$expression = $currentKey;
34-
$runtime = \JmesPath\Env::createRuntime();
3535

3636
if (isset($args['file']) || isset($args['suite']) || isset($args['case'])) {
37-
3837
if (!isset($args['file']) || !isset($args['suite']) || !isset($args['case'])) {
3938
die($description);
4039
}
41-
4240
// Manually run a compliance test
4341
$path = realpath($args['file']);
4442
file_exists($path) or die('File not found at ' . $path);
4543
$json = json_decode(file_get_contents($path), true);
4644
$set = $json[$args['suite']];
4745
$data = $set['given'];
48-
4946
if (!isset($expression)) {
5047
$expression = $set['cases'][$args['case']]['expression'];
5148
echo "Expects\n=======\n";
@@ -57,12 +54,12 @@
5754
echo "NULL\n\n";
5855
}
5956
}
60-
6157
} elseif (isset($expression)) {
6258
// Pass in an expression and STDIN as a standalone argument
6359
$data = json_decode(stream_get_contents(STDIN), true);
6460
} else {
6561
die($description);
6662
}
6763

68-
$runtime->debug($expression, $data);
64+
$runtime = new DebugRuntime(Env::createRuntime());
65+
$runtime($expression, $data);

bin/perf.php

Lines changed: 22 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,19 @@
11
#!/usr/bin/env php
22
<?php
3-
require 'vendor/autoload.php';
4-
5-
use JmesPath\Runtime\RuntimeInterface;
6-
7-
$runtime = \JmesPath\Env::createRuntime();
8-
9-
if (!isset($_SERVER['CACHE'])) {
10-
$_SERVER['CACHE'] = false;
11-
}
12-
13-
if (isset($argv[1])) {
14-
$dir = $argv[1];
15-
} else {
16-
$dir = __DIR__ . '/../tests/compliance/perf';
17-
}
3+
require __DIR__ . '/../vendor/autoload.php';
184

5+
$dir = isset($argv[1]) ? $argv[1] : __DIR__ . '/../tests/compliance/perf';
196
is_dir($dir) or die('Dir not found: ' . $dir);
20-
217
// Warm up the runner
22-
$runtime->search('abcdefg', array());
8+
\JmesPath\Env::search('foo', []);
239

2410
$total = 0;
2511
foreach (glob($dir . '/*.json') as $file) {
26-
if (!strpos($file, 'syntax')) {
27-
$total += runSuite($file, $runtime);
28-
}
12+
$total += runSuite($file);
2913
}
14+
echo "\nTotal time: {$total}\n";
3015

31-
echo "\nTotal time: {$total}ms\n";
32-
33-
function runSuite($file, RuntimeInterface $runtime)
16+
function runSuite($file)
3417
{
3518
$contents = file_get_contents($file);
3619
$json = json_decode($contents, true);
@@ -40,43 +23,37 @@ function runSuite($file, RuntimeInterface $runtime)
4023
$total += runCase(
4124
str_replace(getcwd(), '.', $file),
4225
$suite['given'],
43-
$case['expression'],
44-
$runtime
26+
$case['expression']
4527
);
4628
}
4729
}
48-
4930
return $total;
5031
}
5132

52-
function runCase(
53-
$file,
54-
$given,
55-
$expression,
56-
RuntimeInterface $runtime
57-
) {
33+
function runCase($file, $given, $expression)
34+
{
5835
$best = 99999;
36+
$runtime = \JmesPath\Env::createRuntime();
5937

6038
for ($i = 0; $i < 1000; $i++) {
61-
if (!$_SERVER['CACHE']) {
62-
$runtime->clearCache();
63-
}
64-
try {
65-
$t = microtime(true);
66-
$runtime->search($expression, $given);
67-
$tryTime = (microtime(true) - $t) * 1000;
68-
} catch (\Exception $e) {
69-
// Failure test cases shouldn't be tested
70-
return 0;
71-
}
39+
$t = microtime(true);
40+
$runtime($expression, $given);
41+
$tryTime = (microtime(true) - $t) * 1000;
7242
if ($tryTime < $best) {
7343
$best = $tryTime;
7444
}
45+
if (!getenv('CACHE')) {
46+
$runtime = \JmesPath\Env::createRuntime();
47+
// Delete compiled scripts if not caching.
48+
if ($runtime instanceof \JmesPath\CompilerRuntime) {
49+
array_map('unlink', glob(sys_get_temp_dir() . '/jmespath_*.php'));
50+
}
51+
}
7552
}
7653

77-
$template = "time: %fms, description: %s, name: %s\n";
54+
$template = "time: %fms, %s: %s\n";
7855
$expression = str_replace("\n", '\n', $expression);
79-
printf($template, $best, $file, $expression);
56+
printf($template, $best, basename($file), substr($expression, 0, 50));
8057

8158
return $best;
8259
}

composer.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,15 @@
2323
"autoload": {
2424
"psr-4": {
2525
"JmesPath\\": "src/"
26-
}
26+
},
27+
"files": ["src/JmesPath.php"]
2728
},
2829

2930
"bin": ["bin/jp.php"],
3031

3132
"extra": {
3233
"branch-alias": {
33-
"dev-master": "1.1-dev"
34+
"dev-master": "2.0-dev"
3435
}
3536
}
3637
}

src/AstRuntime.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
namespace JmesPath;
3+
4+
/**
5+
* Uses an external tree visitor to interpret an AST.
6+
*/
7+
class AstRuntime
8+
{
9+
private $parser;
10+
private $interpreter;
11+
private $cache = [];
12+
private $cachedCount = 0;
13+
14+
public function __construct(
15+
Parser $parser = null,
16+
callable $fnDispatcher = null
17+
) {
18+
$fnDispatcher = $fnDispatcher ?: FnDispatcher::getInstance();
19+
$this->interpreter = new TreeInterpreter($fnDispatcher);
20+
$this->parser = $parser ?: new Parser();
21+
}
22+
23+
/**
24+
* Returns data from the provided input that matches a given JMESPath
25+
* expression.
26+
*
27+
* @param string $expression JMESPath expression to evaluate
28+
* @param mixed $data Data to search. This data should be data that
29+
* is similar to data returned from json_decode
30+
* using associative arrays rather than objects.
31+
*
32+
* @return mixed|null Returns the matching data or null
33+
*/
34+
public function __invoke($expression, $data)
35+
{
36+
if (!isset($this->cache[$expression])) {
37+
// Clear the AST cache when it hits 1024 entries
38+
if (++$this->cachedCount > 1024) {
39+
$this->cache = [];
40+
$this->cachedCount = 0;
41+
}
42+
$this->cache[$expression] = $this->parser->parse($expression);
43+
}
44+
45+
return $this->interpreter->visit($this->cache[$expression], $data);
46+
}
47+
}

0 commit comments

Comments
 (0)