diff --git a/.gitattributes b/.gitattributes index 7f822be..34ec487 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,6 +2,8 @@ /build export-ignore /tests export-ignore +/resources/data/Zip32_11208.json.zip +/resources/data/Zip32_11208.csv.zip .editorconfig export-ignore .gitattributes export-ignore .gitignore export-ignore @@ -9,3 +11,4 @@ .php_cs export-ignore .travis.yml export-ignore phpunit.xml.dist export-ignore + diff --git a/.nitpick.json b/.nitpick.json deleted file mode 100644 index 3881d8d..0000000 --- a/.nitpick.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "ignore": [ - "tests/*" - ] -} diff --git a/.php_cs b/.php_cs deleted file mode 100644 index 53e4c34..0000000 --- a/.php_cs +++ /dev/null @@ -1,114 +0,0 @@ - [ - 'syntax' => 'short', - ], - 'binary_operator_spaces' => [ - 'align_double_arrow' => false, - 'align_equals' => false, - ], - 'blank_line_after_namespace' => true, - 'blank_line_after_opening_tag' => true, - 'blank_line_before_return' => true, - 'braces' => true, - 'cast_spaces' => true, - 'class_definition' => true, - 'concat_space' => [ - 'spacing' => 'none', - ], - 'declare_equal_normalize' => true, - 'elseif' => true, - 'encoding' => true, - 'full_opening_tag' => true, - 'function_declaration' => true, - 'function_typehint_space' => true, - 'hash_to_slash_comment' => true, - 'heredoc_to_nowdoc' => true, - 'include' => true, - 'indentation_type' => true, - 'lowercase_cast' => true, - 'lowercase_constants' => true, - 'lowercase_keywords' => true, - 'method_argument_space' => true, - 'method_separation' => true, - 'native_function_casing' => true, - 'no_alias_functions' => true, - 'no_blank_lines_after_class_opening' => true, - 'no_blank_lines_after_phpdoc' => true, - 'no_closing_tag' => true, - 'no_empty_phpdoc' => true, - 'no_empty_statement' => true, - 'no_extra_consecutive_blank_lines' => true, - 'no_leading_import_slash' => true, - 'no_leading_namespace_whitespace' => true, - 'no_mixed_echo_print' => true, - 'no_multiline_whitespace_around_double_arrow' => true, - 'no_multiline_whitespace_before_semicolons' => true, - 'no_short_bool_cast' => true, - 'no_singleline_whitespace_before_semicolons' => true, - 'no_spaces_after_function_name' => true, - 'no_spaces_inside_parenthesis' => true, - 'no_trailing_comma_in_list_call' => true, - 'no_trailing_comma_in_singleline_array' => true, - 'no_trailing_whitespace_in_comment' => true, - 'no_trailing_whitespace' => true, - 'no_unneeded_control_parentheses' => true, - 'no_unreachable_default_argument_value' => true, - 'no_unused_imports' => true, - 'no_useless_return' => true, - 'no_whitespace_before_comma_in_array' => true, - 'no_whitespace_in_blank_line' => true, - 'normalize_index_brace' => true, - 'not_operator_with_successor_space' => true, - 'object_operator_without_whitespace' => true, - 'ordered_class_elements' => true, - 'ordered_imports' => [ - 'sortAlgorithm' => 'length', - ], - 'phpdoc_indent' => true, - 'phpdoc_inline_tag' => true, - 'phpdoc_no_access' => true, - 'phpdoc_no_package' => true, - 'phpdoc_no_useless_inheritdoc' => true, - 'phpdoc_scalar' => true, - 'phpdoc_single_line_var_spacing' => true, - 'phpdoc_summary' => true, - 'phpdoc_to_comment' => true, - 'phpdoc_trim' => true, - 'phpdoc_types' => true, - 'phpdoc_var_without_name' => true, - 'phpdoc_var_without_name' => true, - 'psr4' => true, - 'self_accessor' => true, - 'short_scalar_cast' => true, - 'simplified_null_return' => true, - 'single_blank_line_at_eof' => true, - 'single_blank_line_before_namespace' => true, - 'single_class_element_per_statement' => true, - 'single_import_per_statement' => true, - 'single_line_after_imports' => true, - 'single_quote' => true, - 'space_after_semicolon' => true, - 'standardize_not_equals' => true, - 'switch_case_semicolon_to_colon' => true, - 'switch_case_space' => true, - 'ternary_operator_spaces' => true, - 'trailing_comma_in_multiline_array' => true, - 'trim_array_spaces' => true, - 'unary_operator_spaces' => true, - 'visibility_required' => [ - 'method', - 'property', - ], - 'whitespace_after_comma_in_array' => true, -]; - -return Config::create() - ->setFinder(Finder::create()->in(__DIR__)) - ->setRules($rules) - ->setRiskyAllowed(true) - ->setUsingCache(true); diff --git a/.scrutinizer.yml b/.scrutinizer.yml deleted file mode 100644 index 6fad5be..0000000 --- a/.scrutinizer.yml +++ /dev/null @@ -1,21 +0,0 @@ -filter: - excluded_paths: [tests/*] - -checks: - php: - remove_extra_empty_lines: true - remove_php_closing_tag: true - remove_trailing_whitespace: true - fix_use_statements: - remove_unused: true - preserve_multiple: false - preserve_blanklines: true - order_alphabetically: true - fix_php_opening_tag: true - fix_linefeed: true - fix_line_ending: true - fix_identation_4spaces: true - fix_doc_comments: true - -tools: - external_code_coverage: true diff --git a/.styleci.yml b/.styleci.yml deleted file mode 100644 index 916d27e..0000000 --- a/.styleci.yml +++ /dev/null @@ -1,3 +0,0 @@ -preset: laravel - -linting: true diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index c8ae8ca..0000000 --- a/.travis.yml +++ /dev/null @@ -1,44 +0,0 @@ -language: php - -php: - - 5.5.9 - - 5.5 - - 5.6 - - 7.0 - - 7.1 - - 7.2 - - hhvm - -env: - global: - - setup=basic - -sudo: false - -matrix: - allow_failures: - - php: hhvm - fast_finish: true - include: - - php: 5.5.9 - env: setup=lowest - - php: hhvm - dist: trusty - -cache: - directories: - - $HOME/.composer/cache - -before_install: - - travis_retry composer self-update - -install: - - if [[ $setup = 'basic' ]]; then travis_retry composer install --no-interaction --prefer-dist --no-suggest; fi - - if [[ $setup = 'stable' ]]; then travis_retry composer update --prefer-dist --no-interaction --prefer-stable --no-suggest; fi - - if [[ $setup = 'lowest' ]]; then travis_retry composer update --prefer-dist --no-interaction --prefer-lowest --prefer-stable --no-suggest; fi - -script: vendor/bin/phpunit --coverage-text --coverage-clover=coverage.clover - -after_script: - - wget https://scrutinizer-ci.com/ocular.phar - - php ocular.phar code-coverage:upload --format=php-clover coverage.clover diff --git a/phpcs.xml b/phpcs.xml deleted file mode 100644 index bb63b97..0000000 --- a/phpcs.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - *.blade.php - *.twig.php - bootstrap/ - node_modules/ - public/build/ - public/css/ - public/js/ - public/vendor/ - resources/assets/ - resources/views/ - storage/ - vendor/ - diff --git a/resources/Zip32_11208.json.zip b/resources/Zip32_11208.json.zip new file mode 100644 index 0000000..9373398 Binary files /dev/null and b/resources/Zip32_11208.json.zip differ diff --git a/resources/Zip32_utf8_10501_1.zip b/resources/Zip32_utf8_10501_1.zip deleted file mode 100644 index 0e469b2..0000000 Binary files a/resources/Zip32_utf8_10501_1.zip and /dev/null differ diff --git a/resources/converter.php b/resources/converter.php index 5441faf..2c5d8e0 100644 --- a/resources/converter.php +++ b/resources/converter.php @@ -2,21 +2,21 @@ include __DIR__.'/../vendor/autoload.php'; -use Recca0120\Twzipcode\Sources\CSV; +use Recca0120\Twzipcode\Sources\Csv; +use Recca0120\Twzipcode\Sources\Json; use Recca0120\Twzipcode\Storages\File; +// https://data.gov.tw/dataset/5948 +$downloadUrl = 'https://quality.data.gov.tw/dq_download_json.php?nid=5948&md5_url=e1f6004ad33eb3ff3a824fb992a4b01a'; +$extension = 'json'; +$file = __DIR__.'/Zip32_11208.'.$extension.'.zip'; + set_error_handler(static function ($severity, $message, $file, $line) { throw new ErrorException($message, $severity, $severity, $file, $line); }); -$start = microtime(true); -$file = __DIR__.'/Zip32_utf8_10501_1.zip'; - -// https://data.gov.tw/dataset/5948 -$url = 'https://quality.data.gov.tw/dq_download_csv.php?nid=5948&md5_url=e1f6004ad33eb3ff3a824fb992a4b01a'; - -if (file_exists($file) === false) { - touch($file); +function csv($url) +{ $contents = file_get_contents($url); $encoding = mb_detect_encoding($contents, ['UCS-2LE', 'BIG5', 'UTF-8']); @@ -30,11 +30,29 @@ throw new RuntimeException($contents); } + return $contents; +} + +function json($url) +{ + return file_get_contents($url); +} + +$start = microtime(true); +if (file_exists($file) === false) { + $contents = $extension($downloadUrl); + + touch($file); $zip = new ZipArchive; $zip->open($file, ZipArchive::OVERWRITE); - $zip->addFromString(pathinfo($file, PATHINFO_FILENAME).'.csv', $contents); + $zip->addFromString(pathinfo($file, PATHINFO_FILENAME).'.'.$extension, $contents); $zip->close(); } -(new File)->load(new CSV($file)); +$lookup = ['csv' => Csv::class, 'json' => Json::class]; +$class = $lookup[$extension]; + +$source = new $class($file); + +(new File)->load($source); echo 'benchmark: '.(microtime(true) - $start)."\n"; diff --git a/resources/data/zip5.rules b/resources/data/zip5.rules index 75270a0..6b87d0a 100644 Binary files a/resources/data/zip5.rules and b/resources/data/zip5.rules differ diff --git a/ruleset.xml b/ruleset.xml deleted file mode 100644 index 88a68d6..0000000 --- a/ruleset.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - 1 - - - - - - 1 - - - - - - diff --git a/src/Address.php b/src/Address.php index 13da642..9c5a3a4 100644 --- a/src/Address.php +++ b/src/Address.php @@ -21,9 +21,6 @@ class Address /** @var Normalizer */ public $normalizer; - /** @var Tricky */ - public $tricky; - /** @var JArray */ public $tokens = []; diff --git a/src/Rule.php b/src/Rule.php index dabf7c7..f426d44 100644 --- a/src/Rule.php +++ b/src/Rule.php @@ -138,7 +138,8 @@ private function tokenize($rule, Closure $addressResolver) '[連至單雙全](?=[\d全]|$)', ]; - $addressResolver($this->normalize($rule)->replace('/'.implode('|', $pattern).'/u', + $addressResolver($this->normalize($rule)->replace( + '/'.implode('|', $pattern).'/u', function ($m) use (&$tokens) { $token = &$m[0]; if ($token === '連') { @@ -148,7 +149,8 @@ function ($m) use (&$tokens) { $tokens[] = $token; return $token === '附號全' ? '號' : ''; - })); + } + )); return $tokens; } @@ -187,8 +189,11 @@ private function normalizeAddress(Address $address, JArray $ruleAddressTokens) return new Address( new JArray($address->tokens()->filter(function ($token) use ($removeUnits) { - return isset($token[Address::UNIT]) === true && in_array($token[Address::UNIT], $removeUnits, - true) === false; + return isset($token[Address::UNIT]) === true && in_array( + $token[Address::UNIT], + $removeUnits, + true + ) === false; })->map(function ($token) { return implode('', $token); })) diff --git a/src/Rules.php b/src/Rules.php index 692051b..8864ec7 100644 --- a/src/Rules.php +++ b/src/Rules.php @@ -14,9 +14,6 @@ class Rules */ private $storage; - /** - * @param Storage|null $storage - */ public function __construct(Storage $storage = null) { $this->storage = $storage ?: new File; diff --git a/src/Sources/CSV.php b/src/Sources/Csv.php similarity index 94% rename from src/Sources/CSV.php rename to src/Sources/Csv.php index e00710b..6f32253 100644 --- a/src/Sources/CSV.php +++ b/src/Sources/Csv.php @@ -2,7 +2,7 @@ namespace Recca0120\Twzipcode\Sources; -class CSV extends Source +class Csv extends Source { /** @var string */ protected $file; diff --git a/src/Sources/Json.php b/src/Sources/Json.php new file mode 100644 index 0000000..1324844 --- /dev/null +++ b/src/Sources/Json.php @@ -0,0 +1,21 @@ + $data['郵遞區號'], + 'county' => $data['縣市名稱'], + 'district' => $data['鄉鎮市區'], + 'rule' => implode(',', $data), + ]; + }, json_decode($this->contents(), true)); + } +} diff --git a/src/Sources/Source.php b/src/Sources/Source.php index a611bec..72ad37c 100644 --- a/src/Sources/Source.php +++ b/src/Sources/Source.php @@ -33,10 +33,15 @@ protected function rows() return ! empty(trim($line)); }); - return array_map(static function ($line) { - $data = explode(',', $line); + return array_map(static function ($rule) { + $data = explode(',', $rule); - return ['zipcode' => $data[0], 'county' => $data[1], 'district' => $data[2], 'text' => $line]; + return [ + 'zipcode' => $data[0], + 'county' => $data[1], + 'district' => $data[2], + 'rule' => $rule, + ]; }, $lines); } @@ -51,7 +56,7 @@ protected static function prepare($rows) ? self::$tricks[$row['county'].$row['district']] : substr($row['zipcode'], 0, 3); - $results[$row['county']][$row['district']][$zip3][] = $row['text']; + $results[$row['county']][$row['district']][$zip3][] = $row['rule']; return $results; }, []); diff --git a/src/Tricky.php b/src/Tricky.php index 55034c5..f2ebe78 100644 --- a/src/Tricky.php +++ b/src/Tricky.php @@ -6,6 +6,7 @@ class Tricky { /** @var Tricky */ private static $instance; + private static $cached = []; /* @@ -87,7 +88,7 @@ public function flip($token) public static function instance() { if (! self::$instance) { - self::$instance = new self(); + self::$instance = new self; self::$instance->init(); } diff --git a/src/Zipcode.php b/src/Zipcode.php index 7dd777a..f1ca275 100644 --- a/src/Zipcode.php +++ b/src/Zipcode.php @@ -16,7 +16,6 @@ class Zipcode /** * @param string|Address $address - * @param ?Rules $rules */ public function __construct($address, Rules $rules = null) { @@ -44,7 +43,6 @@ public function __construct($address, Rules $rules = null) /** * @param string|Address $address - * @param ?Rules $rules * @return static */ public static function parse($address, Rules $rules = null) diff --git a/tests/NormalizerKaohsiungTest.php b/tests/NormalizerKaohsiungTest.php index b7bf323..8c41889 100644 --- a/tests/NormalizerKaohsiungTest.php +++ b/tests/NormalizerKaohsiungTest.php @@ -1396,7 +1396,8 @@ public function testNormalizeKaohsiungAddress() ); $this->assertSame( '高雄市桃源區梅山里', - (string) Normalizer::factory('高雄縣桃源鄉梅山村')->normalizeAddress()); + (string) Normalizer::factory('高雄縣桃源鄉梅山村')->normalizeAddress() + ); $this->assertSame( '高雄市那瑪夏區達卡努瓦里', (string) Normalizer::factory('高雄縣那瑪夏鄉達卡努瓦村')->normalizeAddress() diff --git a/tests/Sources/CsvTest.php b/tests/Sources/CsvTest.php new file mode 100644 index 0000000..dd9e85d --- /dev/null +++ b/tests/Sources/CsvTest.php @@ -0,0 +1,42 @@ +setContents('10058,臺北市,中正區,八德路1段,全 +10079,臺北市,中正區,三元街,單全 +'); + + $source->each(function ($zipcode, $county, $district, $rules) { + self::assertEquals(100, $zipcode); + self::assertEquals('臺北市', $county); + self::assertEquals('中正區', $district); + self::assertEquals([ + '10058,臺北市,中正區,八德路1段,全', + '10079,臺北市,中正區,三元街,單全', + ], $rules); + }); + } +} + +class StubCsv extends Csv +{ + private $contents = ''; + + public function setContents($contents) + { + $this->contents = $contents; + } + + public function contents() + { + return $this->contents; + } +} diff --git a/tests/Sources/JsonTest.php b/tests/Sources/JsonTest.php new file mode 100644 index 0000000..3c928c4 --- /dev/null +++ b/tests/Sources/JsonTest.php @@ -0,0 +1,40 @@ +setContents('[{"郵遞區號":"10058","縣市名稱":"臺北市","鄉鎮市區":"中正區","原始路名":"八德路1段","投遞範圍":"全"},{"郵遞區號":"10079","縣市名稱":"臺北市","鄉鎮市區":"中正區","原始路名":"三元街","投遞範圍":"單全"}]'); + + $source->each(function ($zipcode, $county, $district, $rules) { + self::assertEquals(100, $zipcode); + self::assertEquals('臺北市', $county); + self::assertEquals('中正區', $district); + self::assertEquals([ + '10058,臺北市,中正區,八德路1段,全', + '10079,臺北市,中正區,三元街,單全', + ], $rules); + }); + } +} + +class StubJson extends Json +{ + private $contents = ''; + + public function setContents($contents) + { + $this->contents = $contents; + } + + public function contents() + { + return $this->contents; + } +} diff --git a/tests/Storages/FileTest.php b/tests/Storages/FileTest.php index 7dfc3a6..a6454fa 100644 --- a/tests/Storages/FileTest.php +++ b/tests/Storages/FileTest.php @@ -7,7 +7,7 @@ use org\bovigo\vfs\vfsStream; use PHPUnit\Framework\TestCase; use Recca0120\Twzipcode\Address; -use Recca0120\Twzipcode\Sources\CSV; +use Recca0120\Twzipcode\Sources\Json; use Recca0120\Twzipcode\Sources\Text; use Recca0120\Twzipcode\Storages\File as Storage; @@ -125,7 +125,7 @@ public function testLoadResources() Storage::$cached = ['zip3' => null, 'zip5' => null]; $root = vfsStream::setup(); $storage = new Storage($root->url()); - $storage->flush()->load(new CSV(__DIR__.'/../../resources/Zip32_utf8_10501_1.zip')); + $storage->flush()->load(new Json(__DIR__.'/../../resources/Zip32_11208.json.zip')); $address = m::mock(Address::class);