Загрузить файл с помощью Ajax в Laravel 10

Привет, друзья,

Сегодня я объясню простой пример того, как загрузить файл с помощью Laravel 10 и ajax. В этом видео показано, как использовать Ajax для загрузки файла в папку в Laravel 10. В этом руководстве мы покажем вам, как загрузить файл на примере ajax и jQuery в Laravel 10. Этот пример проведет вас через Пошаговое руководство по загрузке файлов Ajax для Laravel 10. В приложении Laravel 10 нам часто нужно сохранять данные файла с помощью ajax-запроса без перезагрузки страницы. Я покажу, как загрузить файл с помощью ajax-вызова в этом руководстве по загрузке файлов Jquery в Laravel 10. Кроме того, мы рассмотрим, как проверить файл перед его загрузкой на сервер.

Загрузить файл с помощью ajax в Laravel и сохранить его в базе данных довольно просто, если вы знакомы с отправкой форм Laravel с использованием ajax. Укажите путь, куда вы хотите поместить загруженный файл при вызове метода хранилища.

В Laravel 10 загрузка файлов с помощью Ajax-запроса довольно проста. Давайте начнем наш учебник по загрузке файла ajax laravel 10 с нуля.

Шаг 1: Загрузите Laravel

Установка свежего приложения Laravel запустит учебник. Если проект уже создан, пропустите следующий шаг.

composer create-project laravel/laravel example-app

Шаг 2: Добавьте миграцию и модель

Здесь мы создадим миграцию для таблицы «файлы», давайте запустим следующую команду и обновим код.

php artisan make:migration create_images_table

2022_02_23_054554_create_images_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('images', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('images');
    }
};

Затем запустите создание новой миграции с помощью команды миграции laravel, как показано ниже:

php artisan migrate

Теперь мы создадим модель файла с помощью следующей команды:

php artisan make:model File

приложение/Модели/Файл.php

<?php
  
namespace App\Models;
  
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
  
class File extends Model
{
    use HasFactory;

    protected $table = 'images';
  
    protected $fillable = [
        'name'
    ];
}

Step 3: Add Controller

In this step, we will create a new FileUploadController; in this file, we will add two method index() and store() for render view and store files into folder and database logic.

Let's create FileUploadController by following command:

php artisan make:controller FileUploadController

next, let's update the following code to Controller File.

app/Http/Controllers/FileUploadController.php

<?php
  
namespace App\Http\Controllers;
  
use Illuminate\Http\Request;
use App\Models\File;
  
class FileUploadController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        return view('fileUpload');
    }
      
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $request->validate([
            'file' => 'required|mimes:doc,docx,pdf,zip,rar|max:2048',
        ]);
        
        $fileName = time().'.'.$request->file->extension();  
         
        $request->file->move(public_path('file'), $fileName);
      
        File::create(['name' => $fileName]);
        
        return response()->json('File uploaded successfully');
    }
}

Store Files in Storage Folder

$file->storeAs('files', $fileName);

// storage/app/files/file.pdf

Store Files in Public Folder

$file->move(public_path('files'), $fileName);

// public/files/file.pdf

Store Files in S3

    $file->storeAs('files', $fileName, 's3');

Step 4: Add Routes

Furthermore, open routes/web.php file and add the routes to manage GET and POST requests for render view and store file logic.

routes/web.php

<?php
  
use Illuminate\Support\Facades\Route;
  
use App\Http\Controllers\FileUploadController;
  
/* 
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
  
Route::controller(FileUploadController::class)->group(function(){
    Route::get('file-upload', 'index');
    Route::post('file-upload', 'store')->name('file.store');
});

Step 5: Add Blade File

At last step we need to create fileUpload.blade.php file and in this file we will create form with file input button and written jquery ajax code. So copy bellow and put on that file.

resources/views/fileUpload.blade.php

<!DOCTYPE html>
<html>
<head>
    <title>How to Upload File using Ajax in Laravel 10? </title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>
<body>
       
<div class="container">
         
    <div class="panel panel-primary card mt-5">
    
        <div class="panel-heading text-center mt-4">
            <h2>How to Upload File using Ajax in Laravel 10?</h2>
        </div>
   
        <div class="panel-body card-body">
           
            <form action="{{ route('file.store') }}" method="POST" id="file-upload" enctype="multipart/form-data">
                @csrf
        
                <div class="mb-3">
                    <label class="form-label" for="inputFile">Select File:</label>
                    <input 
                        type="file" 
                        name="file" 
                        id="inputFile"
                        class="form-control">
                    <span class="text-danger" id="file-input-error"></span>
                </div>
         
                <div class="mb-3">
                    <button type="submit" class="btn btn-success">Upload</button>
                </div>
            
            </form>
        
        </div>
    </div>

</div>

</body>
  
<script type="text/javascript">

    $.ajaxSetup({
        headers: {
            'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
        }
    });
  
    $('#file-upload').submit(function(e) {
        e.preventDefault();
        let formData = new FormData(this);
        $('#file-input-error').text('');

        $.ajax({
            type:'POST',
            url: "{{ route('file.store') }}",
            data: formData,
            contentType: false,
            processData: false,
            success: (response) => {
                if (response) {
                    this.reset();
                    alert('File has been uploaded successfully');
                }
            },
            error: function(response){
                $('#file-input-error').text(response.responseJSON.message);
            }
       });
    });
      
</script>
      
</html>

Run Laravel App:

Все шаги выполнены, теперь вам нужно ввести данную команду и нажать Enter, чтобы запустить приложение laravel:

php artisan serve

Теперь вам нужно открыть веб-браузер, ввести указанный URL-адрес и просмотреть вывод приложения:

http://localhost:8000/file-upload

Я надеюсь, что это может помочь вам...

Оригинальный источник статьи: https://www.nicesnippets.com/

#laravel #ajax #file 

Загрузить файл с помощью Ajax в Laravel 10
木村  直子

木村 直子

1678528141

在 Laravel 10 中使用 Ajax 上传文件

嗨朋友们,

今天,我将解释一个简单的示例,说明如何使用 Laravel 10 和 ajax 上传文件。该视频向您展示了如何使用 Ajax 将文件上传到 Laravel 10 中的文件夹。在本教程中,我们将向您展示如何使用 Laravel 10 中的 ajax 和 jQuery 示例上传文件。该示例将引导您完成Laravel 10 分步 Ajax 文件上传教程。对于 Laravel 10 应用程序,我们经常需要在不重新加载页面的情况下使用 ajax 请求保存文件数据。我将在 Laravel 10 Jquery 文件上传教程中演示如何使用 ajax 调用上传文件。此外,我们还将了解如何在将文件上传到服务器之前验证文件。

如果您熟悉使用 ajax 的 Laravel 表单提交,那么在 Laravel 中使用 ajax 上传文件并将其保存到数据库是非常简单的。调用store方法时指定要放置上传文件的路径。

在 Laravel 10 中,使用 Ajax 请求上传文件非常简单。让我们从头开始我们的 laravel 10 ajax 文件上传教程。

第 1 步:下载 Laravel

安装一个新的 Laravel 应用程序将开始本教程。如果项目已经创建,则跳过下一步。

composer create-project laravel/laravel example-app

第 2 步:添加迁移和模型

在这里,我们将为“文件”表创建迁移,让我们运行下面的命令并更新代码。

php artisan make:migration create_images_table

2022_02_23_054554_create_images_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('images', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('images');
    }
};

接下来,使用 laravel 迁移命令运行创建新迁移,如下所示:

php artisan migrate

现在我们将使用以下命令创建文件模型:

php artisan make:model File

应用程序/模型/File.php

<?php
  
namespace App\Models;
  
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
  
class File extends Model
{
    use HasFactory;

    protected $table = 'images';
  
    protected $fillable = [
        'name'
    ];
}

第 3 步:添加控制器

在这一步中,我们将创建一个新的 FileUploadController;在这个文件中,我们将添加两个方法 index() 和 store() 用于呈现视图并将文件存储到文件夹和数据库逻辑中。

让我们通过以下命令创建 FileUploadController:

php artisan make:controller FileUploadController

接下来,让我们将以下代码更新到 Controller File。

应用程序/Http/Controllers/FileUploadController.php

<?php
  
namespace App\Http\Controllers;
  
use Illuminate\Http\Request;
use App\Models\File;
  
class FileUploadController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        return view('fileUpload');
    }
      
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $request->validate([
            'file' => 'required|mimes:doc,docx,pdf,zip,rar|max:2048',
        ]);
        
        $fileName = time().'.'.$request->file->extension();  
         
        $request->file->move(public_path('file'), $fileName);
      
        File::create(['name' => $fileName]);
        
        return response()->json('File uploaded successfully');
    }
}

将文件存储在存储文件夹中

$file->storeAs('files', $fileName);

// storage/app/files/file.pdf

将文件存储在公用文件夹中

$file->move(public_path('files'), $fileName);

// public/files/file.pdf

在 S3 中存储文件

    $file->storeAs('files', $fileName, 's3');

第 4 步:添加路线

此外,打开 routes/web.php 文件并添加路由来管理渲染视图和存储文件逻辑的 GET 和 POST 请求。

路线/web.php

<?php
  
use Illuminate\Support\Facades\Route;
  
use App\Http\Controllers\FileUploadController;
  
/* 
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
  
Route::controller(FileUploadController::class)->group(function(){
    Route::get('file-upload', 'index');
    Route::post('file-upload', 'store')->name('file.store');
});

第 5 步:添加刀片文件

最后一步我们需要创建 fileUpload.blade.php 文件,在这个文件中我们将创建带有文件输入按钮的表单和编写的 jquery ajax 代码。所以复制下面的内容并放在那个文件上。

资源/视图/fileUpload.blade.php

<!DOCTYPE html>
<html>
<head>
    <title>How to Upload File using Ajax in Laravel 10? </title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>
<body>
       
<div class="container">
         
    <div class="panel panel-primary card mt-5">
    
        <div class="panel-heading text-center mt-4">
            <h2>How to Upload File using Ajax in Laravel 10?</h2>
        </div>
   
        <div class="panel-body card-body">
           
            <form action="{{ route('file.store') }}" method="POST" id="file-upload" enctype="multipart/form-data">
                @csrf
        
                <div class="mb-3">
                    <label class="form-label" for="inputFile">Select File:</label>
                    <input 
                        type="file" 
                        name="file" 
                        id="inputFile"
                        class="form-control">
                    <span class="text-danger" id="file-input-error"></span>
                </div>
         
                <div class="mb-3">
                    <button type="submit" class="btn btn-success">Upload</button>
                </div>
            
            </form>
        
        </div>
    </div>

</div>

</body>
  
<script type="text/javascript">

    $.ajaxSetup({
        headers: {
            'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
        }
    });
  
    $('#file-upload').submit(function(e) {
        e.preventDefault();
        let formData = new FormData(this);
        $('#file-input-error').text('');

        $.ajax({
            type:'POST',
            url: "{{ route('file.store') }}",
            data: formData,
            contentType: false,
            processData: false,
            success: (response) => {
                if (response) {
                    this.reset();
                    alert('File has been uploaded successfully');
                }
            },
            error: function(response){
                $('#file-input-error').text(response.responseJSON.message);
            }
       });
    });
      
</script>
      
</html>

运行 Laravel 应用程序:

所有步骤都已完成,现在您必须键入给定的命令并按回车键来运行 laravel 应用程序:

php artisan serve

现在,您必须打开 Web 浏览器,输入给定的 URL 并查看应用程序输出:

http://localhost:8000/file-upload

我希望它可以帮助你...

文章原文出处:https: //www.nicesnippets.com/

#laravel #ajax #file 

在 Laravel 10 中使用 Ajax 上传文件
Lawson  Wehner

Lawson Wehner

1678524360

Upload File using Ajax in Laravel 10

Hi friends,

Today, I'll explain a straightforward example of how to upload a file using Laravel 10 and ajax. This video shows you how to use Ajax to upload a file to a folder in Laravel 10. In this tutorial, we'll show you how to upload a file using an example of ajax and jQuery in Laravel 10. This example walks you through the Ajax file upload tutorial for Laravel 10 step-by-step. With a Laravel 10 application, we frequently need to save the file data with an ajax request without reloading the page. I'll demonstrate how to upload a file using an ajax call in this Laravel 10 Jquery File Upload tutorial. Also, we'll look at how to verify a file before uploading it to a server.

Uploading a file using ajax in Laravel and saving it to the database is quite simple if you are familiar with Laravel form submission using ajax. Specify the path where you want to put the uploaded file when calling the store method.

In Laravel 10, uploading files using an Ajax request is quite simple. Let's begin our tutorial on laravel 10 ajax file upload from scratch.

Step 1: Download Laravel

Installing a fresh Laravel application will kick off the tutorial. If the project has already been created, skip the next step.

composer create-project laravel/laravel example-app

Step 2: Add Migration and Model

Here, we will create migration for "files" table, let's run bellow command and update code.

php artisan make:migration create_images_table

2022_02_23_054554_create_images_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('images', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('images');
    }
};

Next, run create new migration using laravel migration command as bellow:

php artisan migrate

Now we will create File model by using following command:

php artisan make:model File

app/Models/File.php

<?php
  
namespace App\Models;
  
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
  
class File extends Model
{
    use HasFactory;

    protected $table = 'images';
  
    protected $fillable = [
        'name'
    ];
}

Step 3: Add Controller

In this step, we will create a new FileUploadController; in this file, we will add two method index() and store() for render view and store files into folder and database logic.

Let's create FileUploadController by following command:

php artisan make:controller FileUploadController

next, let's update the following code to Controller File.

app/Http/Controllers/FileUploadController.php

<?php
  
namespace App\Http\Controllers;
  
use Illuminate\Http\Request;
use App\Models\File;
  
class FileUploadController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        return view('fileUpload');
    }
      
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $request->validate([
            'file' => 'required|mimes:doc,docx,pdf,zip,rar|max:2048',
        ]);
        
        $fileName = time().'.'.$request->file->extension();  
         
        $request->file->move(public_path('file'), $fileName);
      
        File::create(['name' => $fileName]);
        
        return response()->json('File uploaded successfully');
    }
}

Store Files in Storage Folder

$file->storeAs('files', $fileName);

// storage/app/files/file.pdf

Store Files in Public Folder

$file->move(public_path('files'), $fileName);

// public/files/file.pdf

Store Files in S3

    $file->storeAs('files', $fileName, 's3');

Step 4: Add Routes

Furthermore, open routes/web.php file and add the routes to manage GET and POST requests for render view and store file logic.

routes/web.php

<?php
  
use Illuminate\Support\Facades\Route;
  
use App\Http\Controllers\FileUploadController;
  
/* 
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
  
Route::controller(FileUploadController::class)->group(function(){
    Route::get('file-upload', 'index');
    Route::post('file-upload', 'store')->name('file.store');
});

Step 5: Add Blade File

At last step we need to create fileUpload.blade.php file and in this file we will create form with file input button and written jquery ajax code. So copy bellow and put on that file.

resources/views/fileUpload.blade.php

<!DOCTYPE html>
<html>
<head>
    <title>How to Upload File using Ajax in Laravel 10? </title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>
<body>
       
<div class="container">
         
    <div class="panel panel-primary card mt-5">
    
        <div class="panel-heading text-center mt-4">
            <h2>How to Upload File using Ajax in Laravel 10?</h2>
        </div>
   
        <div class="panel-body card-body">
           
            <form action="{{ route('file.store') }}" method="POST" id="file-upload" enctype="multipart/form-data">
                @csrf
        
                <div class="mb-3">
                    <label class="form-label" for="inputFile">Select File:</label>
                    <input 
                        type="file" 
                        name="file" 
                        id="inputFile"
                        class="form-control">
                    <span class="text-danger" id="file-input-error"></span>
                </div>
         
                <div class="mb-3">
                    <button type="submit" class="btn btn-success">Upload</button>
                </div>
            
            </form>
        
        </div>
    </div>

</div>

</body>
  
<script type="text/javascript">

    $.ajaxSetup({
        headers: {
            'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
        }
    });
  
    $('#file-upload').submit(function(e) {
        e.preventDefault();
        let formData = new FormData(this);
        $('#file-input-error').text('');

        $.ajax({
            type:'POST',
            url: "{{ route('file.store') }}",
            data: formData,
            contentType: false,
            processData: false,
            success: (response) => {
                if (response) {
                    this.reset();
                    alert('File has been uploaded successfully');
                }
            },
            error: function(response){
                $('#file-input-error').text(response.responseJSON.message);
            }
       });
    });
      
</script>
      
</html>

Run Laravel App:

All steps have been done, now you have to type the given command and hit enter to run the laravel app:

php artisan serve

Now, you have to open web browser, type the given URL and view the app output:

http://localhost:8000/file-upload

I hope it can help you...

Original article source at: https://www.nicesnippets.com/

#laravel #ajax #file 

Upload File using Ajax in Laravel 10
Lawrence  Lesch

Lawrence Lesch

1678216860

HFS: A Web File Server to Run on Your Computer

HFS: HTTP File Server (version 3)


Introduction

HFS is the best way via web to access or share files from your disk.

  • It's a server software, share files fresh from your disk. Don't rely on services, be independent!
  • It's all very fast. Try download zipping 100GB, it starts immediately!
  • Easy to use. HFS tries to detect problems and suggest solutions.
  • Share even a single file with our virtual file system, even with a different name, all without touching the real file. Present things the way you want!
  • Watch all activities in real-time.
  • Control bandwidth, decide how much to give.

This is a full rewrite of the Delphi version.

How does it work

  • run HFS on your computer, administration page automatically shows up
  • select what files and folders you want to be accessible
  • possibly create accounts and limit access to files
  • access those files from a phone or another computer just using a browser

Features

  • https
  • unicode
  • virtual file system
  • mobile friendly front-end
  • search
  • accounts
  • resumable downloads
  • resumable uploads
  • download folders as zip archive
  • remote delete
  • simple website serving
  • plug-ins
  • log file
  • speed throttler
  • admin web interface
  • multi-language front-end
  • virtual hosting (plug-in)
  • anti-brute-force (plug-in)

Installation

  1. go to https://github.com/rejetto/hfs/releases
  2. click on Assets
  3. download the right version for your computer
  4. launch hfs file
  5. the browser should automatically open on localhost address, so you can configure the rest in the Admin-panel.
    • if a browser cannot be opened on the computer where you are installing HFS, you should enter this command in HFS console: create-admin <PASSWORD>

If you access Admin-panel via localhost, by default HFS won't require you to login. If you don't like this behavior, disable it in the Admin-panel or enter this console command config localhost_admin false.

Other systems

If your system is not Windows/Linux/Mac, you can try this alternative version:

  1. install node.js
  2. execute: sudo npm -g i hfs
  3. launch: hfs

Configuration and other files will be stored in %HOME%/.vfs

With this installation method, you can update with sudo npm -g update hfs .

Service

If you want to run HFS as a service

  • if you installed with npm on Windows
    • service installation
      • run npx qckwinsvc2 install name="HFS" description="HFS" path="%APPDATA%\npm\node_modules\hfs\src\index.js" args="--cwd %HOMEPATH%\.hfs" now
    • service update
      • run npx qckwinsvc2 uninstall name="HFS"
      • run npm -g update hfs
      • run the service installation again

Internationalization

It is possible to show the Front-end in other languages. In the Languages section of the Admin-panel you'll be able to install lang files. You can find some of these files at https://github.com/rejetto/hfs/tree/main/langs To download a file: open it, right-click on the "Raw" button, Save.

Files must be named hfs-lang-CODE.json (lowercase), where CODE is the ISO code for your language (e.g. pt-br for Brazilian).

Translation is applied automatically based on the configuration of the visitor's browser. Check the language configuration of your browser.

Plug-ins

To install a plugin you just copy its folder inside plugins folder.

Delete it to uninstall.

HFS will ignore all folders with -disabled at the end of the name.

Why you should upgrade from HFS 2.x to 3

As you can see from the list of features, we already have some goods that you cannot find in HFS 2. Other than that, you can also consider:

  • it's more robust: it was designed to be an always-running server, while HFS 1-2 was designed for occasional usage (transfer and quit)
  • passwords are never really stored, just a non-reversible hash is
  • faster search (up to 12x)
  • more flexible permissions

But you may still want to stay with HFS 2.x (so far) for the following reasons

  • smaller
  • more tested
  • classic window interface (can be easier for some people)

Console commands

If you have access to HFS' console, you can enter commands. Start with help to have a full list.

Configuration

Configuration can be done in several ways

  • accessing the Admin-panel with your browser
  • after HFS has started you can enter console command in the form config NAME VALUE
  • passing via command line at start in the form --NAME VALUE
  • directly editing the config.yaml file. As soon as you save it is reloaded and changes are applied

NAME stands for the property name that you want to change. See the complete list below.

Where is it stored

Configuration is stored in the file config.yaml, which is stored in the same folder of hfs.exe if you are using this kind of distribution on Windows, or USER_FOLDER/.hfs on other systems.

You can decide a different file and location by passing --config SOME_FILE at command line, or inside an env called HFS_CONFIG. Any relative path provided is relative to the cwd.

Configuration properties

  • port where to accept http connections. Default is 80.
  • vfs the files and folders you want to expose. For details see the dedicated following section.
  • log path of the log file. Default is access.log.
  • log_rotation frequency of log rotation. Accepted values are daily, weekly, monthly, or empty string to disable. Default is weekly.
  • error_log path of the log file for errors. Default is error.log.
  • errors_in_main_log if you want to use a single file for both kind of entries. Default is false.
  • accounts list of accounts. For details see the dedicated following section.
  • mime command what mime-type to be returned with some files. E.g.: "*.jpg": image/jpeg You can specify multiple entries, or separate multiple file masks with a p|pe. You can use the special value auto to attempt automatic detection.
  • max_kbps throttle output speed. Default is Infinity.
  • max_kbps_per_ip throttle output speed on a per-ip basis. Default is Infinity.
  • zip_calculate_size_for_seconds how long should we wait before the zip archive starts streaming, trying to understand its finale size. Default is 1.
  • open_browser_at_start should HFS open browser on localhost on start? Default is true.
  • https_port listen on a specific port. Default is 443.
  • cert use this file for https certificate. Minimum to start https is to give a cert and a private_key. Default is none.
  • private_key use this file for https private key. Default is none.
  • allowed_referer you can decide what domains can link to your files. Wildcards supported. Default is empty, meaning any.
  • block a list of rules that will block connections. E.g.:
block:
  - ip: 192.168.0.90
  • Syntax supports, other than simple address, * as wildcard and CIDR format.
  • plugins_config this is a generic place where you can find/put configuration for each plugin, at least those that need configuration.
  • enable_plugins if a plugin is not present here, it won't run. Defaults is [ antibrute ].
  • localhost_admin should Admin be accessed without credentials when on localhost. Default is true.
  • proxies number of proxies between server and clients to be trusted about providing clients' IP addresses. Default is 0.
  • keep_unfinished_uploads should unfinished uploads be deleted immediately when interrupted. Default is true.
  • favicon path to file to be used as favicon. Default is none.

Virtual File System (VFS)

The virtual file system is a tree of files and folders, collectively called nodes. By default, a node is a folder, unless you provide for it a source that's a file. Valid keys in a node are:

  • name: this is the name we'll use to display this file/folder. If not provided, HFS will infer it from the source. At least name or source must be provided.
  • source: absolute or relative path of where to get the content
  • children: just for folders, specify its virtual children. Value is a list and its entries are nodes.
  • rename: similar to name, but it's from the parent node point. Use this to change the name of entries that are read from the source, not listed in the VFS. Value is a dictionary, where the key is the original name.
  • mime: specify what mime to use for this resource. Use "auto" for automatic detection.
  • default: to be used with a folder where you want to serve a default html. E.g.: "index.html". Using this will make mime default to "auto".
  • can_read: specify who can download this entry. Value is a WhoCan descriptor, which is one of these values
    • true: anyone can, even people who didn't log in. This is normally the default value.
    • false: no one can.
    • "*": any account can, i.e. anyone who logged in.
    • [ frank, peter ]: the list of accounts who can.
  • can_see: specify who can see this entry. Even if a user can download you can still make the file not appear in the list. Remember that to see in the list you must also be able to download (read), or else you won't see it anyway. Value is a WhoCan descriptor, refer above.
  • can_upload specify who can upload. Applies to folders with a source. Default is none.
  • can_delete specify who can delete. Applies to folders with a source. Default is none.
  • masks: maps a file mask to a set of properties as the one documented in this section. E.g.
"**/*.mp3":
  can_read: false
"*.jpg|*.png": 
  mime: auto

Permissions set on an inner element will override inherited permissions. This means that you can restrict access to folder1, and yet decide to give free access to folder1/subfolder2.

Accounts

All accounts go under accounts: property, as a dictionary where the key is the username. E.g.

accounts:
    admin:
        password: hello123
        belongs: group1
    guest:
        password: guest
    group1:

As soon as the config is read HFS will encrypt passwords (if necessary) in a non-reversible way. It means that password property is replaced with an encrypted property: srp.

As you can see in the example, group1 has no password. This implies that you cannot log in as group1, but still group1 exists and its purpose is to gather multiple accounts and refer to them collectively as group1, so you can quickly share powers among several accounts.

For each account entries, this is the list of properties you can have:

  • ignore_limits to ignore speed limits. Default is false.
  • redirect provide a URL if you want the user to be redirected upon login. Default is none.
  • admin set true if you want to let this account log in to the Admin-panel. Default is false.
  • belongs an array of usernames of other accounts from which to inherit their permissions. Default is none.

Download Details:

Author: Rejetto
Source Code: https://github.com/rejetto/hfs 
License: GPL-3.0 license

#typescript #nodejs #web #file #http #server

HFS: A Web File Server to Run on Your Computer
Lawson  Wehner

Lawson Wehner

1677909420

Count Files in Directory in Linux

Count Files in Directory in Linux

Although not very often, there are times when you need to find out how many files are in a given directory. For example, if you run out of inodes on your Linux system, you’ll need to find which directory contains thousands or millions of files.

In this article, we will show you several different ways to find the number of files in a directory in Linux.

Count Files in Directory

The simplest way to count files in a directory is to list one file per line with ls and pipe the output to wc to count the lines:

ls -1U DIR_NAME | wc -l

The command above will give you a sum of all files, including directories and symlinks. The -1 option means list one file per line and -U tells ls to do not sort the output which makes the execution of the command faster.

ls -1U command doesn’t count hidden files (dotfiles).

If you want to count only files and not include the directories use the following:

ls -1Up DIR_NAME | grep -v / | wc -l

The -p option forces ls to append slash (/) indicator to directories. The output is piped to the grep -v command that exclude the directories.

To have more control over what files are listed, use the find command instead of ls:

find DIR_NAME -maxdepth 1 -type f | wc -l

-type f option tells find to list only files (including dotfiles), and -maxdepth 1 limit search to the first-level directory.

Recursively Count Files in Directory

To recursively count files in directory run the find command as follows:

find DIR_NAME -type f | wc -l

Another command that can be used to count files is tree that lists contents of directories in a tree-like format:

tree DIR_NAME

The last line of output will show the total number of files and directories listed:

15144 directories, 91311 files

Conclusion

We have shown you how to count files in directory using the ls, find and tree commands.

Original article source at: https://linuxize.com/

#linux #file 

Count Files in Directory in Linux

GslibIO.jl: Utilities to Read/write Extended GSLIB Files in Julia

GslibIO.jl

Utilities to read/write extended and legacy GSLIB files in Julia.


Overview

The GSLIB file format was introduced a long time ago for storing geospatial data over Cartesian grids or point sets in text files that are easy to read. Unfortantely, the format specification is incomplete:

Cartesian grids

  • it doesn't contain the size of the grid (i.e. (nx, ny, nz))
  • it doesn't specify the origin and spacing (i.e. (ox, oy, oz), (sx, sy, sz))
  • it doesn't specify the special symbol for inactive cells (e.g. -999)

Point sets

  • it doesn't specify which variable names are geospatial coordinates

This package introduces an extended GSLIB format that addresses these issues. It also provides helper functions to load data in legacy format.

Installation

Get the latest stable release with Julia's package manager:

] add GslibIO

Usage

Please use save and load for the extended GSLIB file format and save_legacy and load_legacy for the legacy GSLIB file format. Consult the docstring of each function for more information.

An usual workflow consists of loading a legacy file with load_legacy by setting the options manually, and then saving the data back to disk in extended format with save. The new extended format can then be loaded without human intervention.

using GslibIO

# load grid data stored in legacy format
data = GslibIO.load_legacy("legacy.gslib", (100,100,50), na=-999)

# save grid data in new extended format
GslibIO.save("extended.gslib", data)

# now it can be loaded without special options
GslibIO.load("extended.gslib")

Download Details:

Author: JuliaEarth
Source Code: https://github.com/JuliaEarth/GslibIO.jl 
License: MIT license

#julia #file #format 

GslibIO.jl: Utilities to Read/write Extended GSLIB Files in Julia
Gordon  Murray

Gordon Murray

1677091800

Export & Download Data As A CSV File in Spring Boot

Export & Download Data As A CSV File in Spring Boot

A Comma-Separated Values (CSV) file is a plain text file that uses a comma as a delimiter to separate values. It stores data in a tabular format where each row consists of one or more fields, and each column represents a specific field.

CSV is a widely used data exchange format in the industry due to its simplicity and better integration with existing applications. These files are usually used for exporting and importing large data sets.

In this tutorial, we shall learn how to export and download the data as a CSV file in a Spring Boot project. Data export (JSON, CSV, PDF, etc.) is a common feature implemented in many Java enterprise applications.

Project Dependencies

Since Java does not provide native support for creating and parsing CSV files, we shall use OpenCSV, a 3rd-party library for parsing and creating CSV files.

Here is what our build.gradle file looks like:

build.gradle

plugins {
    id 'org.springframework.boot' version '2.1.3.RELEASE'
    id 'java'
}

apply plugin: 'io.spring.dependency-management'

group = 'com.attacomsian'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'com.opencsv:opencsv:4.5'
}

If you are working with a maven project, make sure you include the following maven dependency to the project's pom.xml file:

<dependency>
    <groupId>com.opencsv</groupId>
    <artifactId>opencsv</artifactId>
    <version>4.5</version>
</dependency>

User Model

Here is our User model class being used to write to a CSV file.

User.java

package com.attacomsian.exportcsv.data;

import com.opencsv.bean.CsvBindByName;
import com.opencsv.bean.CsvBindByPosition;

public class User {

    private long id;
    private String name;
    private String email;
    private String country;
    private int age;

    public User(long id, String name, String email, String country, int age) {
        this.id = id;
        this.name = name;
        this.email = email;
        this.country = country;
        this.age = age;
    }
    
    // getters and setters removed for the sake of brevity
 }

Since we want to generate a CSV file from a list of users and then return it to the client for downloading, let's create a dummy service that acts as a data source and returns a list of users.

UserService.java

package com.attacomsian.exportcsv.data;

import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class UserService {

    public List<User> listUsers() {
        List<User> users = new ArrayList<>();

        //create dummy users
        users.add(new User(1, "Jack Lee", "jack@example.com", "Germany", 35));
        users.add(new User(2, "Jovan Srovoki", "jovan@srovoki.me", "Russia", 21));
        users.add(new User(3, "Atta", "atta@gmail.com", "Pakistan", 29));

        return users;
    }
}

The UserService above is just for demo purposes. You may want to populate a list of users from the database or any other source.

Generate & Download CSV File

The following Spring MVC controller class handles the export and download of data as a CSV file.

UserController.java

package com.attacomsian.exportcsv.controllers;

import com.attacomsian.exportcsv.data.User;
import com.attacomsian.exportcsv.data.UserService;
import com.opencsv.CSVWriter;
import com.opencsv.bean.ColumnPositionMappingStrategy;
import com.opencsv.bean.StatefulBeanToCsv;
import com.opencsv.bean.StatefulBeanToCsvBuilder;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

import javax.servlet.http.HttpServletResponse;

@Controller
public class UserController {

    private UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/export-users")
    public void exportCSV(HttpServletResponse response) throws Exception {

        //set file name and content type
        String filename = "users.csv";

        response.setContentType("text/csv");
        response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
                "attachment; filename=\"" + filename + "\"");

        //create a csv writer
        StatefulBeanToCsv<User> writer = new StatefulBeanToCsvBuilder<User>(response.getWriter())
                .withQuotechar(CSVWriter.NO_QUOTE_CHARACTER)
                .withSeparator(CSVWriter.DEFAULT_SEPARATOR)
                .withOrderedResults(false)
                .build();

        //write all users to csv file
        writer.write(userService.listUsers());
                
    }
}

The above UserController class contains an exportCSV() method that is mapped to /export-users HTTP route and returns a CSV file as attachment for browser to download. This method does the following:

  • Set the response's content type to text/csv.
  • Use HttpHeaders.CONTENT_DISPOSITION to add "Content-Disposition" response header that indicates file attachment to the browser. It also sets the attachment file name to users.csv
  • Use response writer (response.writer() returns an object of type PrintWriter) to build an instance of StatefulBeanToCsv.
  • Use write() method of StatefulBeanToCsv instance to write a list of users to CSV file.
  • Afterwards, the data is pushed to the client where the browser downloads the attached users.csv file.

Running the Application

Below is the main application class used for running the Spring Boot project:

Application.java

package com.attacomsian.exportcsv;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

Let's run the application by typing the following command in your terminal from the root directory of the project:

$ ./gradlew bootRun

After the Spring Boot application is started, open http://localhost:8080/export-users link in your favorite browser to generate and download the users.csv file. Here is the content of the generated CSV file:

users.csv

age,country,email,id,name
35,Germany,jack@example.com,1,Jack Lee
21,Russia,jovan@srovoki.me,2,Jovan Srovoki
29,Pakistan,atta@gmail.com,3,Atta

Notice the first line. OpenCSV automatically generated column headers using User class members. Another thing to note is the order of the columns in the CSV file. OpenCSV sorts the column names in ascending order before writing them into the CSV file.

OpenCSV Columns Ordering

There is no built-in functionality in OpenCSV that allows writing bean to CSV with custom column names and ordering. However, using the @CsvBindByPosition annotation, you can control the column positions in the generated CSV file. But the downside of this annotation is that it removes column headers from the generated CSV file.

public class User {

    @CsvBindByPosition(position = 0)
    private long id;
    @CsvBindByPosition(position = 1)
    private String name;
    @CsvBindByPosition(position = 2)
    private String email;
    @CsvBindByPosition(position = 3)
    private String country;
    @CsvBindByPosition(position = 4)
    private int age;

    //constructor, getting and settings 
}

@CsvBindByPosition specifies a binding between a column number of the CSV file and a field in a bean. This column number is zero-based (means position starts from 0).

Source code: Download the complete source code from GitHub available under MIT license.

Conclusion

That's all for explaining the usage of the OpenCSV library to generate and download a CSV file in Spring Boot. If you are uncomfortable using a 3rd-party library, you can write your own CSV writer. Writing a CSV file is similar to writing a text file with few exceptions.

Original article source at: https://attacomsian.com/

#springboot #csv #file 

Export & Download Data As A CSV File in Spring Boot
Gordon  Murray

Gordon Murray

1677087660

How to Save Textarea Text To A File using JavaScript

How to Save Textarea Text To A File using JavaScript

In this article, you will learn how to convert Textarea Text to File using JavaScript. This is a great project for beginners. There is a box here, you can convert the contents of that box into a file. Many times in a project you need to save the text content to the file later. In that case, you can use this JavaScript Create and Save text file project.

 We usually use Notepad when we want to create any kind of files like HTML, CSS, or text. This project will make that task much easier. There is a small box in which you can input some text or information. 

Then there is another small box where you can use the rename of your choice. Then there is a download button that will save the file by clicking on it.

Save Text to a File in JavaScript

I used JavaScript, HTML, and CSS to create this project. First, we created its basic structure using HTML CSS. Then I implemented this project (Create and Save the text file in JavaScript) using JavaScript.

First I designed the webpage and made a box on it. I added a heading at the beginning of this box. The h1 tag has been used to enhance this heading. Then I created a box using HTML’s Textarea. In this box, you can input some text. Then create another input box in which you can add the rename of the file of your choice. Here you can create any type of file.

 If you open this Create and save a file project with a browser, your content will be downloaded automatically. If you open it using a code editor, you will be asked for permission to download the file.

How to save textbox value to file using JavaScript

To build it you need to have a basic idea about HTML CSS and JavaScript. The video below will help you learn how it works.

You can also use the demo section above to know How to save form data in a Text file using JavaScript. If you just want the source code, you can use the download button at the bottom of the article. However, I request you to follow the step-by-step tutorials below. 

Below I have shown step-by-step how to save text to a client-side file using JavaScript. Hereafter each step I have given possible results which will help you to understand better.

Step 1: Basic structure of Text to a File project

I have created the basics of this project (Create and Save the text file in JavaScript) using the following HTML and CSS code. 

A box has been created here with width: 430px and the background color is white. Here I have used the background-color blue of the webpage.

<div id=”container”>
 
</div>
* {
  box-sizing: border-box;
}
body {
  height: 100vh;
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #044b82;
  font-family: “Kanit”, Verdana, Arial, sans-serif;
}
#container {
  width: 430px;
  padding: 40px 20px;
  background: white;
}
Basic structure of Text to a File project

Step 2: Add a heading using HTML

Now I have added a heading that will be at the very beginning of this box. HTML’s h1 tag has been used to create this heading. I used font-size: 30px and color blue to increase the text size.

 <h1>Save the text to a file</h1>
h1 {
  color: #0773d7;
  font-size: 30px;
  width: 100%;
  margin-top: -15px;
  margin-bottom: 30px;
  text-align: center;
  text-transform: uppercase;
}
Add a heading using HTML

Step 3: Create a box using Textarea

Now a box has been created to input the text or contents. This box has been created with the help of HTML Textarea.

<textarea placeholder=”Type your text here…” id=”text”></textarea>
#text {
  display: block;
  width: 100%;
  background-color: transparent;
  color: #021652;
  border: 2px solid #3ba9f4;
  border-radius: 2px;
  resize: none;
  margin-bottom: 35px;
  height: 200px;
  padding: 10px;
  font-size: 20px;
}
Create a box using Textarea

Step 4: Create a place to input the file name

Now a box has been created to input the file name. This box is created using the input function of HTML. The width of the box is 100% and the height of the box is 50px.

<input id=”filename” placeholder=”Specify a filename…” />
#filename {
  width: calc(100% – 200px);
  border: 2px solid #3ba9f4;
  border-radius: 2px;
  background-color: transparent;
  color: #052a53;
  padding: 0 10px;
  height: 50px;
  line-height: 50px;
  font-size: 20px;
  margin-right: 20px;
}
Create a place to input the file name

Step 5: Button to save text to a file

Now it needs to create a download button. Clicking on this button will download all the text files. Box width: 174px, height: 50px and background color blue has been used.

<button id=”download”>Download file</button>
#download {
  background-color: #3ba9f4;
  color: #fff;
  font-size: 20px;
  height: 50px;
  border: none;
  border-radius: 2px;
  width: 174px;
  cursor: pointer;
}
Button to save the file

Step 6: Save Text to a File using JavaScript

This project has been implemented using the following JavaScript. If you know Basic JavaScript, you can easily create this project (Save Textarea Text to a File using JavaScript).

 Here I have put the necessary information at the top of each line why I used that code. I hope the following explanations will help you to understand this JavaScript.

function downloadFile(filename, content) {
  // It works on all HTML5 Ready browsers as it uses the download attribute of the <a> element:
  const element = document.createElement(‘a’);
  
  //A blob is a data type that can store binary data
  // “type” is a MIME type
  // It can have a different value, based on a file you want to save
  const blob = new Blob([content], { type: ‘plain/text’ });
  //createObjectURL() static method creates a DOMString containing a URL representing the object given in the parameter.
  const fileUrl = URL.createObjectURL(blob);
  
  //setAttribute() Sets the value of an attribute on the specified element.
  element.setAttribute(‘href’, fileUrl); //file location
  element.setAttribute(‘download’, filename); // file name
  element.style.display = ‘none’;
  
  //use appendChild() method to move an element from one element to another
  document.body.appendChild(element);
  element.click();
  
  //The removeChild() method of the Node interface removes a child node from the DOM and returns the removed node
  document.body.removeChild(element);
};
window.onload = () => {
  document.getElementById(‘download’).
  addEventListener(‘click’, e => {
    
    //The value of the file name input box
    const filename = document.getElementById(‘filename’).value;
    
    //The value of what has been input in the textarea
    const content = document.getElementById(‘text’).value;
    
    // The && (logical AND) operator indicates whether both operands are true. If both operands have nonzero values, the result has the value 1 . Otherwise, the result has the value 0.
    
    if (filename && content) {
      downloadFile(filename, content);
    }
  });
};
Save Text to a File using JavaScript

If there is any problem then, of course, you can follow the video tutorial. Hopefully, the above tutorial has helped you to know how to convert text to file using JavaScript

If there is any difficulty then you can definitely let me know by commenting. If you like this project (How to save textbox value to file) then be sure to share it with your friends.

Original article source at: https://foolishdeveloper.com/

#javascript #file #save #text 

How to Save Textarea Text To A File using JavaScript

How to Linux File Encryption

How to Linux File Encryption

Linux file encryption involves rewriting the plaintext documents into a format that can only be accessed by those with the right password or decryption key. This is done to prevent the unauthorized access to delicate information. Linux supports a number of encryption methods including symmetric encryption which employs the very same key for encryption and decryption, filesystem-level encryption, and public-private key asymmetric encryption. Linux users frequently use GnuPG, OpenSSL, and dm-crypt as encryption tools. In this guide, we will use the GPG utility to encrypt the Linux files and decrypt them.

Update the System

The first thing to do is to update your system before the installation of any utility. The following command updates the package list on an Ubuntu system. Using the “sudo” command, the “omar” user runs the command with superuser rights.  The system is connected to a package repository at “http://pk.archive.ubuntu.com/ubuntu” and is looking for updates.

omar@virtualbox:~$ sudo apt-get update

Install the GPG

The GPG is the tool that is used in Linux to encrypt the files. The following command is used to install the “gpg” (GNU Privacy Guard) software package on the system. Run the command with administrative rights by typing “sudo.” A utility to manage the packages on Debian-based computers is called “apt-get.” The “install” command instructs the apt-get to set up the chosen “gpg” package. The output shows that the “gpg” package is already installed on the system and is the newest version (2.2.27-3ubuntu2.1). The package is also set to be manually installed which means that it is installed by a user rather than being a dependency of another package. The output also states that two packages, “libflashrom1” and “libftdi1-2”, are no longer required and can be removed using the “apt autoremove” command. Lastly, the output states that there are 0 upgraded packages, 0 newly installed packages, 0 packages to be removed, and 37 un-upgraded packages. No changes are made to the system’s packages and all packages are up-to-date.

omar@virtualbox:~$ sudo apt-get install gpg

File Encryption

To encrypt in Linux, we should have a file with some important content in it. Thus, we use the “touch” instruction to create a new file in the current working directory which is pass.txt.

omar@virtualbox:~$ touch pass.txt

 The “ls” query of Linux shows that the newly created “pass.txt” file is listed in the current working directory.

omar@virtualbox:~$ ls
Desktop    Downloads  new       Pictures  snap       Videos
Documents  Music      pass.txt  Public    Templates

Make sure to add some content to your newly made file. We also add some information regarding our system user in the “pass.txt” file by manually opening it. The “Cat” instruction can be used to display the contents of any sort of file as shown in the attached command and output:

omar@virtualbox:~$ cat pass.txt
Password: Omar

The “gpg -c pass.txt” command uses the GNU Privacy Guard (GPG) tool to encrypt a file called “pass.txt” using the symmetric-key encryption. The “-c” option tells GPG to use the symmetric-key encryption and prompts the user to enter any passphrase to use as the encryption key. The encrypted file is created using the same title as the original file and the “.gpg” file extension.

omar@virtualbox:~$ gpg -c pass.txt

 The dialog box appears on your screen which prompts you to enter the passphrase as shown in the image. We add the passphrase and tapp the “OK” button:


The very next screen shows a warning if you enter an insecure passphrase. Choose the “Take this one anyway” option to proceed.


The list instruction displays the encrypted “pass.txt.gpg” file which is listed with the other files in the current directory.

omar@virtualbox:~$ ls
Desktop       Downloads   new        pass.txt.gpg    Public    Templates
Documents  Music          pass.txt    Pictures          snap       Videos

 The “file” instruction is applied to establish the type of a “pass.txt.gpg” file based on its contents, rather than its file name or file extension. The output indicates that the “pass.txt.gpg” file is a GPG symmetrically encrypted file, and it’s encrypted using the AES256 cipher. The AES256 cipher is a symmetric key encryption algorithm. AES (Advanced Encryption Standard) is a widely used encryption standard, and 256 refers to the key size which means that it has a key size of 256-bit.

omar@virtualbox:~$ file pass.txt.gpg
pass.txt.gpg: GPG symmetrically encrypted data (AES256 cipher)

 Now, when you try to display the contents of an encrypted “pass.txt.gpg” file, we should get the following output using the “Cat” instruction along with the file name:

omar@virtualbox:~$ cat pass.txt.gpg
�       ��7$�Z$��K��^��On���
����k.�K�{��dE�֛_���$�
                     ��6ay�jȚ�N:�*�w�:�껎~��4j

After the encryption of a “pass.txt” file to a new file, there is no need to remain using the original file which is the pass.txt. Therefore, we remove it using the “rm” instruction.

omar@virtualbox:~$ rm pass.txt

File Decryption

It’s time to decrypt the original data from the encrypted “pass.txt.gpg” file. For this, we don’t need the original “pass.txt” file here since we already deleted it as per the “ls” command.

omar@virtualbox:~$ ls
Desktop       Downloads  new              Pictures    snap          Videos
Documents  Music          pass.txt.gpg  Public      Templates

 
To decrypt the encrypted “pass.txt.gpg” file, we cast off the following “gpg” instruction on the shell. It uses the “>” operator to pass the decrypted content to a “pass.txt” file that uses the GNU Privacy Guard (GPG) tool to decrypt a “pass.txt.gpg” file using symmetric-key decryption. The “–decrypt” option tells GPG to perform the decryption, and the “> pass.txt” redirects the output of the decryption process to a file called “pass.txt”.

The first output line indicates that the data in the pass.txt.gpg file is encrypted using the AES256 cipher in CFB(Cipher Feedback) mode. The second output line, “gpg: encrypted with 1 passphrase”, indicates that the pass.txt.gpg file is encrypted with a single passphrase. A passphrase is a sequence of words or other text that is used to encrypt a file, and it is required to decrypt the file.

omar@virtualbox:~$ gpg --decrypt pass.txt.gpg > pass.txt
gpg: AES256.CFB encrypted data
gpg: encrypted with 1 passphrase

Now, we have a pass.txt file back in the current working directory as per the following “ls” instruction output:

omar@virtualbox:~$ ls
Desktop       Downloads  new              pass.txt     Pictures       snap          Videos
Documents  Music          pass.txt.gpg  Public      Templates

When you try to display the content of a pass.txt file on the Linux shell using the cat instruction, it displays the original content before the encryption of a file.

omar@virtualbox:~$ cat pass.txt
Password: Omar

Conclusion

The introduction demonstrates the use of encryption in Linux systems and discusses its types as well. To support the topic, we installed the GPG utility that is specifically designed for the encryption of Linux-based files. After its installation, we generated a simple text file and encrypted it using the “gpg” utility and added the passphrase for encryption as an example. Lastly, we tried the GPG utility to decrypt a file to its original form and display the original content on the shell.

Original article source at: https://linuxhint.com/

#linux #file #encryption 

How to Linux File Encryption
Monty  Boehm

Monty Boehm

1676774280

Read A Text File into an Array using Node.js

Read A Text File into an Array using Node.js

To read a text file into an array in Node.js:

  1. Use the fsPromises.readFile() to read the file contents into a string.
  2. Await until the promise returned by the above method has been resolved.
  3. Use the split() method to split the string into an array of substrings.
const fsPromises = require('fs/promises')

const readFileAsync = async () => {
  try {
    const contents = await fsPromises.readFile('file.txt', 'utf-8')

    const arr = contents.split(/\r?\n/)

    console.log(arr)
    // [ 'this', 'is', 'an', 'example two two', 'text!' ]
  } catch (err) {
    console.error(err)
  }
}

readFileAsync()

The fsPromises.readFile() method takes the path to the file as the first parameter and the encoding as the second. It asynchronously reads the contents of the given file.

If you skip the encoding parameter, fsPromises.readFile() will return a buffer. Otherwise, a string is returned.

We used the String.split() method to split the file contents on each newline character. We did the same for reading a file line by line in Node.js.

In case you need to read the file contents synchronously, use the fs.readFileSync() method instead:

const fs = require('fs')

const contents = fs.readFileSync('file.txt', 'utf-8')

const arr = contents.split(/\r?\n/)

console.log(arr)
// [ 'this', 'is', 'an', 'example two two', 'text!' ]

Original article source at: https://attacomsian.com/

#node #array #text #file 

Read A Text File into an Array using Node.js
Desmond  Gerber

Desmond Gerber

1676660580

Fix Fatal Error: Python.h: No Such File Or Directory

Fix Fatal Error: Python.h: No Such File Or Directory

When you compile C and C++ code using GCC, you might see the following error:

fatal error: Python.h: No such file or directory

This error usually occurs when you add the Python header file to your C code, but that file can’t be found on your system.

This tutorial shows examples that cause this error and how you can fix it.

How to reproduce this error

Suppose you have a file named main.c with the following content:

#include<Python.h>
#include<stdio.h>

int main()
{
    printf("Hello World!\n");
    return 0;
}

You instructed the program to include the Python.h header file, then compile it using GCC:

gcc main.c

When GCC can’t find the Python.h file in your system, it shows the following error:

main.c:1:9: fatal error: Python.h: No such file or directory
    1 | #include<Python.h>
      |         ^~~~~~~~~~
compilation terminated.

To fix this error, you need to make GCC able to find the Python header file.

How to fix this error

If you use Ubuntu OS, the Python.h file is included in the python-dev package.

You can use one of the following commands to install the python-dev package.

If you have Python 3, then install the python3-dev package:

#For apt (Ubuntu, Debian...):
sudo apt-get install python-dev  
sudo apt-get install python3-dev

#For yum (CentOS, RHEL...):
sudo yum install python-devel  
sudo yum install python3-devel 

# For dnf (Fedora...):
sudo dnf install python2-devel 
sudo dnf install python3-devel

#For zypper (openSUSE...):
sudo zypper in python-devel  
sudo zypper in python3-devel

# For apk (Alpine...):
sudo apk add python2-dev 
sudo apk add python3-dev

#For apt-cyg (Cygwin...):
apt-cyg install python-devel  
apt-cyg install python3-devel

Once you install the Python-dev package, you could find the Python.h file in /usr/include/pythonx.xx with x.xx being the version of the Python you installed.

You can also use the locate command to find the file:

$ locate Python.h
/usr/include/python3.10/Python.h

Now that you have the location of Python.h, you need to include the path to that file by adding the -I flag when running GCC.

Here’s an example:

gcc main.c -I/usr/include/python3.10

Notice you no longer get the fatal error. You can run the output file a.out to run the compiled C program.

Fix for macOS

If you use macOS, then the header file should be included when you install Python on your computer.

If you use Homebrew to install Python, the header file should be somewhere in /opt/homebrew/Cellar/ for Apple Silicon Macs or in /usr/local/Cellar for Intel Macs.

I found my header file in /opt/homebrew/Cellar/python@3.10/3.10.10/Frameworks/Python.framework/Versions/3.10/include/python3.10.

You can use the Search bar in Finder to find the file. Find the location by right-clicking on the file and select Get Info.

You can highlight and copy the path shown in the Where info.

Next, you need to include the path when compiling your code with GCC like this:

gcc main.c -I/opt/homebrew/Cellar/python@3.10/3.10.10/Frameworks/Python.framework/Versions/3.10/include/python3.10

The compilation no longer gives a fatal error, and you can run the compiled program.

Conclusion

The fatal error: Python.h: No such file or directory occurs when GCC can’t find the Python.h file you included in your code.

You might not have the python-dev package installed on your system, or the path to Python.h file isn’t included in the PATH variable.

You can add the -I flag when compiling with GCC to include the path to the directory that holds the header file.

Original article source at: https://sebhastian.com/

#python #file #error 

Fix Fatal Error: Python.h: No Such File Or Directory
Hunter  Krajcik

Hunter Krajcik

1674820980

Upload File and Display Preview in CakePHP 4

File uploads are a common feature in web applications. It allows users to upload and share files, such as images, videos, and documents.

CakePHP 4 already has built-in File handling classes to handle file uploads.

In this tutorial, I show how you can upload file with validation and display its preview after upload in CakePHP 4.

In the example, I am using Modelless form for creating an upload form.

1. Create UploadfileForm Form

  • Create UploadfileForm.php file in src/Form/ folder. Create Form folder if it does not exist.
  • Create UploadfileForm class.

Create 3 methods –

  • _buildSchema() – Define HTML form schema data. I am not defining <form > element from here.
  • validationDefault() – Define <form > validation. Here, fileel is the file element name.

Set it as required, and add rules for file type and file size.

  • _execute() – From this method upload the selected file.

Assign file instance to $attachment. Read file details and assign them to the variables.

If $error == 0 then check if uploads folder exists in webroot or not. If not exists then create it.

Upload the file and return true.

NOTE  – Uploaded file will be stored in webroot/uploads/ folder.

Completed Code

<?php 
namespace App\Form;

use Cake\Form\Form;
use Cake\Form\Schema;
use Cake\Validation\Validator;
use Cake\Filesystem\Folder;

class UploadfileForm extends Form
{
      protected function _buildSchema(Schema $schema): Schema
      {
           return $schema;
      }

      public function validationDefault(Validator $validator): Validator
      {

           $validator
               ->notEmptyFile('fileel')
               ->add('fileel', [
                      'mimeType' => [
                           'rule' => ['mimeType',['image/jpg','image/png','image/jpeg','application/pdf']],
                           'message' => 'File type must be .jpg,.jpeg,.png,.pdf',
                      ],
                      'fileSize' => [
                           'rule' => ['fileSize','<', '2MB'],
                           'message' => 'File size must be less than 2MB',
                      ]
               ]);

           return $validator;
      }

      protected function _execute(array $data): bool
      {
           $attachment = $data['fileel'];

           // File details
           $filename = $attachment->getClientFilename();
           $type = $attachment->getClientMediaType();
           $size = $attachment->getSize();
           $extension = pathinfo($filename, PATHINFO_EXTENSION);
           $tmpName = $attachment->getStream()->getMetadata('uri');
           $error = $attachment->getError();

           // Upload file
           if($error == 0){

                 $location = WWW_ROOT . 'uploads' . DS;

                 $folder = new Folder();
                 $checkfolder = $folder->inPath($location, true);
                 if(!$checkfolder){ // Not exists
                      if (!$folder->create($location)) {
                            return false;
                      }
                 }

                 $targetPath = $location.$filename;
                 $attachment->moveTo($targetPath);

                 return true;
           }else{
                 return false;
           }

      }
}

2. Create Controller

  • Create a FileuploadController.php file in src/Controller/ folder.
  • Create FileuploadController Class that extends AppController.
  • Include App\Form\UploadfileForm.

Here, create 1 method –

  • index() – Create instance of UploadfileForm().

If <form > is POST then call $uploadfile->execute() where pass POST data. If it returns true then read file element data for preview.

Assign $filepath to $filedetails['filepath'] and $extension to $filedetails['extension'].

Set filedetails and uploadfile.

Completed Code

<?php
declare(strict_types=1);

namespace App\Controller;
use App\Form\UploadfileForm;

class FileuploadController extends AppController
{

     public function index(){
          $uploadfile = new UploadfileForm();

          $filedetails = array();
          if ($this->request->is('post')) {

                if ($uploadfile->execute($this->request->getData())) {

                      // Read file for preview
                      $attachment = $this->request->getData('fileel');
                      $filename = $attachment->getClientFilename();
                      $extension = pathinfo($filename, PATHINFO_EXTENSION);

                      $filepath = "/uploads/".$filename;
                      $extension = $extension;

                      $filedetails['filepath'] = $filepath;
                      $filedetails['extension'] = $extension;

                      $this->Flash->success('File uploaded successfully.');
                } else {
                      $this->Flash->error('File not uploaded.');
                }
          }

          $this->set('filedetails', $filedetails);
          $this->set('uploadfile', $uploadfile);
     }

}

3. Create Template

Create a new Fileupload folder in templates/ folder. Now in the Fileupload folder create index.php file.

Create a <form > set its action to fileupload/index. Pass $uploadfile as 1st parameter in create(). Here, $uploadfile is an instance of UploadfileForm Class it is set from the controller.

In the <form > create a file element and a submit button.

To display a preview check if $filedetails Array is empty or not.

If not empty then check $filedetails['extension'] extension value. If the extension is image type then create <img > element to display file otherwise create <a > tag to create view link.

Completed Code

<div class="row">
    <div class="col-6">

        <?php 

        // Upload form
        echo $this->Form->create($uploadfile,array('url'=>['controller' => 'fileupload','action' => 'index'],"enctype" => "multipart/form-data" ));
        echo $this->Form->control('fileel',['label' => 'Select file','type' => 'file','class' => 'form-control','required' => true]);
        echo $this->Form->button('Submit');
        echo $this->Form->end();

        ?>

        <?php
        // Preview file
        if(count($filedetails) > 0){
             $image_exts = array("jpg","jpeg","png");
             if(in_array($filedetails['extension'],$image_exts)){
                  echo $this->HTML->image($filedetails['filepath']);
             }else{
                  echo $this->Html->link(
                      'View file',
                      $filedetails['filepath'],
                      ['target' => '_blank']
                  );
             }
        }
        ?>

    </div>
</div>

4. Output

http://localhost:8765/fileupload

View Output


5. Conclusion

If you also want to save the file to the database then you don’t need to create a Modelless Form class. You need to pass ORM Entity in form and handle it in the controller.

If you found this tutorial helpful then don't forget to share.

Original article source at: https://makitweb.com/

#cakephp #php #upload #file 

Upload File and Display Preview in CakePHP 4
Gordon  Murray

Gordon Murray

1673474280

Read CSV File and Display Its Content using JavaScript

In JavaScript FileReader class is available to read the data of the file. Using this you can read and view the file content before uploading it to the server.

In this tutorial, I show how you can use FileReader class to read CSV file and display its content on the page using JavaScript.

1. CSV file structure

In the example, I am using the following file structure –

S.no,Username,Name,Email
1,yssyogesh,Yogesh singh,yogesh@makitweb.com
2,bsonarika,Sonarika Bhadoria,bsonarika@makitweb.com
3,vishal,Vishal Sahu,vishal@makitweb.com
4,anilsingh,Anil singh,anilsingh@makitweb.com

2. HTML

Create a file element and a button. Using <table > to list selected CSV file data. Add onclick event on the button. It calls readCSVFile() function.

Completed Code

<!-- CSS -->
<style type="text/css">
    table th, table td{
    padding: 5px;
}
</style>

<div>

    <div>
         <input type="file" name="file" id="file" accept=".csv" > <br><br>
         <input type="button" id="btnsubmit" value="Submit" onclick="readCSVFile();" >
    </div>

    <br><br>
    <!-- List CSV file data -->
    <table id="tblcsvdata" border="1" style="border-collapse: collapse;">
         <thead>
              <tr>
                  <th>S.no</th>
                  <th>Username</th>
                  <th>Name</th>
                  <th>Email</th>
              </tr>
         </thead>
         <tbody>

         </tbody>

    </table>
</div>

3. JavaScript – Read CSV

Create readCSVFile() function that calls on button click. Check if a file is selected or not.


Read CSV file and Display data –

  • Create an object of FileReader Class if a file is selected.
  • Pass file instance in readAsText() to read its data as a string.
  • Add onload event on the reader object. It calls when the file successfully gets read.
  • Use result property to get file data. Assign the data to csvdata variable.
  • Split the string data by line break (\n) to get data in Array format.
  • Create an instance of <table > <tbody > where need to append data.
  • Loop on the rowData Array. Here, for not reading 1st row I assigned 1 to row variable but you can assign 0 if you want to read 1st row.
  • Create an empty <tr> – tbodyEl.insertRow().
  • Split the row value by comma (,) to get column data Array.
  • Loop on the rowColData Array to read column data. Create a cell and add column value – rowColData[col].

Completed Code

function readCSVFile(){
     var files = document.querySelector('#file').files;

     if(files.length > 0 ){

          // Selected file
          var file = files[0];

          // FileReader Object
          var reader = new FileReader();

          // Read file as string 
          reader.readAsText(file);

          // Load event
          reader.onload = function(event) {

               // Read file data
               var csvdata = event.target.result;

               // Split by line break to gets rows Array
               var rowData = csvdata.split('\n');

               // <table > <tbody>
               var tbodyEl = document.getElementById('tblcsvdata').getElementsByTagName('tbody')[0];
               tbodyEl.innerHTML = "";

               // Loop on the row Array (change row=0 if you also want to read 1st row)
               for (var row = 1; row < rowData.length; row++) {

                     // Insert a row at the end of table
                     var newRow = tbodyEl.insertRow();

                     // Split by comma (,) to get column Array
                     rowColData = rowData[row].split(',');

                     // Loop on the row column Array
                     for (var col = 0; col < rowColData.length; col++) {

                          // Insert a cell at the end of the row
                          var newCell = newRow.insertCell();
                          newCell.innerHTML = rowColData[col];

                     }

               }
          };

     }else{
          alert("Please select a file.");
     }

}

4. Output

View Output


5. Conclusion

You can use this code to display a preview of file data or you can also modify the code for applying validation.

Adjust the code according to your CSV file while implementing this on your project.

If you found this tutorial helpful then don't forget to share.

Original article source at: https://makitweb.com/

#javascript #csv #file 

Read CSV File and Display Its Content using JavaScript
Rupert  Beatty

Rupert Beatty

1673369705

MacOS app Codeable Model file Generator For Swift 5

SwiftyJSONAccelerator - MacOS app Codeable Model file Generator For Swift 5

Version v2.2

Version v2.1

  • Tests are back - major parts of the code is covered.
  • Multiple file model generator is working again.

Version v2.0 (Swift 5)

  • Generates Swift 5 Codeable version along with CodingKeys.
  • Allows support to switch between Optional and non-optional variations.
  • Temporarily support for CLI and tests have been removed.
  • UI now supports Dark mode!

Installing & Building

Building:

pod install

You will also need to install SwiftFormat with brew install swiftformat and SwiftLint with brew install swiftlint.

Download dmg: Download the .app (v2.2.0)

Common Issues

  • SwiftyJSONAccelerator can't be opened because Apple cannot check it for malicious software.: Run the following command xattr -d com.apple.quarantine <app-path>.

Features

Logo

A Swift model generator like the Objective-C JSONAccelerator. Formats and generates models for the given JSON and also breaks them into files making it easy to manage and share between several models.

  • The models that are generated depend Swift's inbuilt Codeable feature making encoding and decoding objects a thing of the past.
  • Allows to opt for either optional or non-optional variables.
  • Allows an array of a certain object type with different properties to be merged into a single model with all properties.
  • Click Load folder with JSON files + Config to generate all possible models for given folder with JSON files, note this needs a .config.json as this uses the CLI logic internally.

Contributions and Requests

Any suggestions regarding code quality of the app, generated code's quality, Swift related improvements and pull requests are all very welcome. Please make sure you submit the pull request to the next release branch and not the master branch.

Download Details:

Author: insanoid
Source Code: https://github.com/insanoid/SwiftyJSONAccelerator 
License: MIT license

#swift #json #file #generator 

MacOS app Codeable Model file Generator For Swift 5
Rupert  Beatty

Rupert Beatty

1673365703

Swift-tips: A Collection Useful Tips for The Swift Language

SwiftTips

The following is a collection of tips I find to be useful when working with the Swift language. More content is available on my Twitter account!

📣 NEW 📣 Swift Tips are now available on YouTube 👇

Tips

Property Wrappers as Debugging Tools

Property Wrappers allow developers to wrap properties with specific behaviors, that will be seamlessly triggered whenever the properties are accessed.

While their primary use case is to implement business logic within our apps, it's also possible to use Property Wrappers as debugging tools!

For example, we could build a wrapper called @History, that would be added to a property while debugging and would keep track of all the values set to this property.

import Foundation

@propertyWrapper
struct History<Value> {
    private var value: Value
    private(set) var history: [Value] = []

    init(wrappedValue: Value) {
        self.value = wrappedValue
    }
    
    var wrappedValue: Value {
        get { value }

        set {
            history.append(value)
            value = newValue
        }
    }
    
    var projectedValue: Self {
        return self
    }
}

// We can then decorate our business code
// with the `@History` wrapper
struct User {
    @History var name: String = ""
}

var user = User()

// All the existing call sites will still
// compile, without the need for any change
user.name = "John"
user.name = "Jane"

// But now we can also access an history of
// all the previous values!
user.$name.history // ["", "John"]

Localization through String interpolation

Swift 5 gave us the possibility to define our own custom String interpolation methods.

This feature can be used to power many use cases, but there is one that is guaranteed to make sense in most projects: localizing user-facing strings.

import Foundation

extension String.StringInterpolation {
    mutating func appendInterpolation(localized key: String, _ args: CVarArg...) {
        let localized = String(format: NSLocalizedString(key, comment: ""), arguments: args)
        appendLiteral(localized)
    }
}


/*
 Let's assume that this is the content of our Localizable.strings:
 
 "welcome.screen.greetings" = "Hello %@!";
 */

let userName = "John"
print("\(localized: "welcome.screen.greetings", userName)") // Hello John!

Implementing pseudo-inheritance between structs

If you’ve always wanted to use some kind of inheritance mechanism for your structs, Swift 5.1 is going to make you very happy!

Using the new KeyPath-based dynamic member lookup, you can implement some pseudo-inheritance, where a type inherits the API of another one 🎉

(However, be careful, I’m definitely not advocating inheritance as a go-to solution 🙃)

import Foundation

protocol Inherits {
    associatedtype SuperType
    
    var `super`: SuperType { get }
}

extension Inherits {
    subscript<T>(dynamicMember keyPath: KeyPath<SuperType, T>) -> T {
        return self.`super`[keyPath: keyPath]
    }
}

struct Person {
    let name: String
}

@dynamicMemberLookup
struct User: Inherits {
    let `super`: Person
    
    let login: String
    let password: String
}

let user = User(super: Person(name: "John Appleseed"), login: "Johnny", password: "1234")

user.name // "John Appleseed"
user.login // "Johnny"

Composing NSAttributedString through a Function Builder

Swift 5.1 introduced Function Builders: a great tool for building custom DSL syntaxes, like SwiftUI. However, one doesn't need to be building a full-fledged DSL in order to leverage them.

For example, it's possible to write a simple Function Builder, whose job will be to compose together individual instances of NSAttributedString through a nicer syntax than the standard API.

import UIKit

@_functionBuilder
class NSAttributedStringBuilder {
    static func buildBlock(_ components: NSAttributedString...) -> NSAttributedString {
        let result = NSMutableAttributedString(string: "")
        
        return components.reduce(into: result) { (result, current) in result.append(current) }
    }
}

extension NSAttributedString {
    class func composing(@NSAttributedStringBuilder _ parts: () -> NSAttributedString) -> NSAttributedString {
        return parts()
    }
}

let result = NSAttributedString.composing {
    NSAttributedString(string: "Hello",
                       attributes: [.font: UIFont.systemFont(ofSize: 24),
                                    .foregroundColor: UIColor.red])
    NSAttributedString(string: " world!",
                       attributes: [.font: UIFont.systemFont(ofSize: 20),
                                    .foregroundColor: UIColor.orange])
}

Using switch and if as expressions

Contrary to other languages, like Kotlin, Swift does not allow switch and if to be used as expressions. Meaning that the following code is not valid Swift:

let constant = if condition {
                  someValue
               } else {
                  someOtherValue
               }

A common solution to this problem is to wrap the if or switch statement within a closure, that will then be immediately called. While this approach does manage to achieve the desired goal, it makes for a rather poor syntax.

To avoid the ugly trailing () and improve on the readability, you can define a resultOf function, that will serve the exact same purpose, in a more elegant way.

import Foundation

func resultOf<T>(_ code: () -> T) -> T {
    return code()
}

let randomInt = Int.random(in: 0...3)

let spelledOut: String = resultOf {
    switch randomInt {
    case 0:
        return "Zero"
    case 1:
        return "One"
    case 2:
        return "Two"
    case 3:
        return "Three"
    default:
        return "Out of range"
    }
}

print(spelledOut)

Avoiding double negatives within guard statements

A guard statement is a very convenient way for the developer to assert that a condition is met, in order for the execution of the program to keep going.

However, since the body of a guard statement is meant to be executed when the condition evaluates to false, the use of the negation (!) operator within the condition of a guard statement can make the code hard to read, as it becomes a double negative.

A nice trick to avoid such double negatives is to encapsulate the use of the ! operator within a new property or function, whose name does not include a negative.

import Foundation

extension Collection {
    var hasElements: Bool {
        return !isEmpty
    }
}

let array = Bool.random() ? [1, 2, 3] : []

guard array.hasElements else { fatalError("array was empty") }

print(array)

Defining a custom init without loosing the compiler-generated one

It's common knowledge for Swift developers that, when you define a struct, the compiler is going to automatically generate a memberwise init for you. That is, unless you also define an init of your own. Because then, the compiler won't generate any memberwise init.

Yet, there are many instances where we might enjoy the opportunity to get both. As it turns out, this goal is quite easy to achieve: you just need to define your own init in an extension rather than inside the type definition itself.

import Foundation

struct Point {
    let x: Int
    let y: Int
}

extension Point {
    init() {
        x = 0
        y = 0
    }
}

let usingDefaultInit = Point(x: 4, y: 3)
let usingCustomInit = Point()

Implementing a namespace through an empty enum

Swift does not really have an out-of-the-box support of namespaces. One could argue that a Swift module can be seen as a namespace, but creating a dedicated Framework for this sole purpose can legitimately be regarded as overkill.

Some developers have taken the habit to use a struct which only contains static fields to implement a namespace. While this does the job, it requires us to remember to implement an empty private init(), because it wouldn't make sense for such a struct to be instantiated.

It's actually possible to take this approach one step further, by replacing the struct with an enum. While it might seem weird to have an enum with no case, it's actually a very idiomatic way to declare a type that cannot be instantiated.

import Foundation

enum NumberFormatterProvider {
    static var currencyFormatter: NumberFormatter {
        let formatter = NumberFormatter()
        formatter.numberStyle = .currency
        formatter.roundingIncrement = 0.01
        return formatter
    }
    
    static var decimalFormatter: NumberFormatter {
        let formatter = NumberFormatter()
        formatter.numberStyle = .decimal
        formatter.decimalSeparator = ","
        return formatter
    }
}

NumberFormatterProvider() // ❌ impossible to instantiate by mistake

NumberFormatterProvider.currencyFormatter.string(from: 2.456) // $2.46
NumberFormatterProvider.decimalFormatter.string(from: 2.456) // 2,456

Using Never to represent impossible code paths

Never is quite a peculiar type in the Swift Standard Library: it is defined as an empty enum enum Never { }.

While this might seem odd at first glance, it actually yields a very interesting property: it makes it a type that cannot be constructed (i.e. it possesses no instances).

This way, Never can be used as a generic parameter to let the compiler know that a particular feature will not be used.

import Foundation

enum Result<Value, Error> {
    case success(value: Value)
    case failure(error: Error)
}

func willAlwaysSucceed(_ completion: @escaping ((Result<String, Never>) -> Void)) {
    completion(.success(value: "Call was successful"))
}

willAlwaysSucceed( { result in
    switch result {
    case .success(let value):
        print(value)
    // the compiler knows that the `failure` case cannot happen
    // so it doesn't require us to handle it.
    }
})

Providing a default value to a Decodable enum

Swift's Codable framework does a great job at seamlessly decoding entities from a JSON stream. However, when we integrate web-services, we are sometimes left to deal with JSONs that require behaviors that Codable does not provide out-of-the-box.

For instance, we might have a string-based or integer-based enum, and be required to set it to a default value when the data found in the JSON does not match any of its cases.

We might be tempted to implement this via an extensive switch statement over all the possible cases, but there is a much shorter alternative through the initializer init?(rawValue:):

import Foundation

enum State: String, Decodable {
    case active
    case inactive
    case undefined
    
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        let decodedString = try container.decode(String.self)
        
        self = State(rawValue: decodedString) ?? .undefined
    }
}

let data = """
["active", "inactive", "foo"]
""".data(using: .utf8)!

let decoded = try! JSONDecoder().decode([State].self, from: data)

print(decoded) // [State.active, State.inactive, State.undefined]

Another lightweight dependency injection through default values for function parameters

Dependency injection boils down to a simple idea: when an object requires a dependency, it shouldn't create it by itself, but instead it should be given a function that does it for him.

Now the great thing with Swift is that, not only can a function take another function as a parameter, but that parameter can also be given a default value.

When you combine both those features, you can end up with a dependency injection pattern that is both lightweight on boilerplate, but also type safe.

import Foundation

protocol Service {
    func call() -> String
}

class ProductionService: Service {
    func call() -> String {
        return "This is the production"
    }
}

class MockService: Service {
    func call() -> String {
        return "This is a mock"
    }
}

typealias Provider<T> = () -> T

class Controller {
    
    let service: Service
    
    init(serviceProvider: Provider<Service> = { return ProductionService() }) {
        self.service = serviceProvider()
    }
    
    func work() {
        print(service.call())
    }
}

let productionController = Controller()
productionController.work() // prints "This is the production"

let mockedController = Controller(serviceProvider: { return MockService() })
mockedController.work() // prints "This is a mock"

Lightweight dependency injection through protocol-oriented programming

Singletons are pretty bad. They make your architecture rigid and tightly coupled, which then results in your code being hard to test and refactor. Instead of using singletons, your code should rely on dependency injection, which is a much more architecturally sound approach.

But singletons are so easy to use, and dependency injection requires us to do extra-work. So maybe, for simple situations, we could find an in-between solution?

One possible solution is to rely on one of Swift's most know features: protocol-oriented programming. Using a protocol, we declare and access our dependency. We then store it in a private singleton, and perform the injection through an extension of said protocol.

This way, our code will indeed be decoupled from its dependency, while at the same time keeping the boilerplate to a minimum.

import Foundation

protocol Formatting {
    var formatter: NumberFormatter { get }
}

private let sharedFormatter: NumberFormatter = {
    let sharedFormatter = NumberFormatter()
    sharedFormatter.numberStyle = .currency
    return sharedFormatter
}()

extension Formatting {
    var formatter: NumberFormatter { return sharedFormatter }
}

class ViewModel: Formatting {
    var displayableAmount: String?
    
    func updateDisplay(to amount: Double) {
        displayableAmount = formatter.string(for: amount)
    }
}

let viewModel = ViewModel()

viewModel.updateDisplay(to: 42000.45)
viewModel.displayableAmount // "$42,000.45"

Getting rid of overabundant [weak self] and guard

Callbacks are a part of almost all iOS apps, and as frameworks such as RxSwift keep gaining in popularity, they become ever more present in our codebase.

Seasoned Swift developers are aware of the potential memory leaks that @escaping callbacks can produce, so they make real sure to always use [weak self], whenever they need to use self inside such a context. And when they need to have self be non-optional, they then add a guard statement along.

Consequently, this syntax of a [weak self] followed by a guard rapidly tends to appear everywhere in the codebase. The good thing is that, through a little protocol-oriented trick, it's actually possible to get rid of this tedious syntax, without loosing any of its benefits!

import Foundation
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

protocol Weakifiable: class { }

extension Weakifiable {
    func weakify(_ code: @escaping (Self) -> Void) -> () -> Void {
        return { [weak self] in
            guard let self = self else { return }
            
            code(self)
        }
    }
    
    func weakify<T>(_ code: @escaping (T, Self) -> Void) -> (T) -> Void {
        return { [weak self] arg in
            guard let self = self else { return }
            
            code(arg, self)
        }
    }
}

extension NSObject: Weakifiable { }

class Producer: NSObject {
    
    deinit {
        print("deinit Producer")
    }
    
    private var handler: (Int) -> Void = { _ in }
    
    func register(handler: @escaping (Int) -> Void) {
        self.handler = handler
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: { self.handler(42) })
    }
}

class Consumer: NSObject {
    
    deinit {
        print("deinit Consumer")
    }
    
    let producer = Producer()
    
    func consume() {
        producer.register(handler: weakify { result, strongSelf in
            strongSelf.handle(result)
        })
    }
    
    private func handle(_ result: Int) {
        print("🎉 \(result)")
    }
}

var consumer: Consumer? = Consumer()

consumer?.consume()

DispatchQueue.main.asyncAfter(deadline: .now() + 2.0, execute: { consumer = nil })

// This code prints:
// 🎉 42
// deinit Consumer
// deinit Producer

Solving callback hell with function composition

Asynchronous functions are a big part of iOS APIs, and most developers are familiar with the challenge they pose when one needs to sequentially call several asynchronous APIs.

This often results in callbacks being nested into one another, a predicament often referred to as callback hell.

Many third-party frameworks are able to tackle this issue, for instance RxSwift or PromiseKit. Yet, for simple instances of the problem, there is no need to use such big guns, as it can actually be solved with simple function composition.

import Foundation

typealias CompletionHandler<Result> = (Result?, Error?) -> Void

infix operator ~>: MultiplicationPrecedence

func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void, _ second: @escaping (T, CompletionHandler<U>) -> Void) -> (CompletionHandler<U>) -> Void {
    return { completion in
        first({ firstResult, error in
            guard let firstResult = firstResult else { completion(nil, error); return }
            
            second(firstResult, { (secondResult, error) in
                completion(secondResult, error)
            })
        })
    }
}

func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void, _ transform: @escaping (T) -> U) -> (CompletionHandler<U>) -> Void {
    return { completion in
        first({ result, error in
            guard let result = result else { completion(nil, error); return }
            
            completion(transform(result), nil)
        })
    }
}

func service1(_ completionHandler: CompletionHandler<Int>) {
    completionHandler(42, nil)
}

func service2(arg: String, _ completionHandler: CompletionHandler<String>) {
    completionHandler("🎉 \(arg)", nil)
}

let chainedServices = service1
    ~> { int in return String(int / 2) }
    ~> service2

chainedServices({ result, _ in
    guard let result = result else { return }
    
    print(result) // Prints: 🎉 21
})

Transform an asynchronous function into a synchronous one

Asynchronous functions are a great way to deal with future events without blocking a thread. Yet, there are times where we would like them to behave in exactly such a blocking way.

Think about writing unit tests and using mocked network calls. You will need to add complexity to your test in order to deal with asynchronous functions, whereas synchronous ones would be much easier to manage.

Thanks to Swift proficiency in the functional paradigm, it is possible to write a function whose job is to take an asynchronous function and transform it into a synchronous one.

import Foundation

func makeSynchrone<A, B>(_ asyncFunction: @escaping (A, (B) -> Void) -> Void) -> (A) -> B {
    return { arg in
        let lock = NSRecursiveLock()
        
        var result: B? = nil
        
        asyncFunction(arg) {
            result = $0
            lock.unlock()
        }
        
        lock.lock()
        
        return result!
    }
}

func myAsyncFunction(arg: Int, completionHandler: (String) -> Void) {
    completionHandler("🎉 \(arg)")
}

let syncFunction = makeSynchrone(myAsyncFunction)

print(syncFunction(42)) // prints 🎉 42

Using KeyPaths instead of closures

Closures are a great way to interact with generic APIs, for instance APIs that allow to manipulate data structures through the use of generic functions, such as filter() or sorted().

The annoying part is that closures tend to clutter your code with many instances of {, } and $0, which can quickly undermine its readably.

A nice alternative for a cleaner syntax is to use a KeyPath instead of a closure, along with an operator that will deal with transforming the provided KeyPath in a closure.

import Foundation

prefix operator ^

prefix func ^ <Element, Attribute>(_ keyPath: KeyPath<Element, Attribute>) -> (Element) -> Attribute {
    return { element in element[keyPath: keyPath] }
}

struct MyData {
    let int: Int
    let string: String
}

let data = [MyData(int: 2, string: "Foo"), MyData(int: 4, string: "Bar")]

data.map(^\.int) // [2, 4]
data.map(^\.string) // ["Foo", "Bar"]

Bringing some type-safety to a userInfo Dictionary

Many iOS APIs still rely on a userInfo Dictionary to handle use-case specific data. This Dictionary usually stores untyped values, and is declared as follows: [String: Any] (or sometimes [AnyHashable: Any].

Retrieving data from such a structure will involve some conditional casting (via the as? operator), which is prone to both errors and repetitions. Yet, by introducing a custom subscript, it's possible to encapsulate all the tedious logic, and end-up with an easier and more robust API.

import Foundation

typealias TypedUserInfoKey<T> = (key: String, type: T.Type)

extension Dictionary where Key == String, Value == Any {
    subscript<T>(_ typedKey: TypedUserInfoKey<T>) -> T? {
        return self[typedKey.key] as? T
    }
}

let userInfo: [String : Any] = ["Foo": 4, "Bar": "forty-two"]

let integerTypedKey = TypedUserInfoKey(key: "Foo", type: Int.self)
let intValue = userInfo[integerTypedKey] // returns 4
type(of: intValue) // returns Int?

let stringTypedKey = TypedUserInfoKey(key: "Bar", type: String.self)
let stringValue = userInfo[stringTypedKey] // returns "forty-two"
type(of: stringValue) // returns String?

Lightweight data-binding for an MVVM implementation

MVVM is a great pattern to separate business logic from presentation logic. The main challenge to make it work, is to define a mechanism for the presentation layer to be notified of model updates.

RxSwift is a perfect choice to solve such a problem. Yet, some developers don't feel confortable with leveraging a third-party library for such a central part of their architecture.

For those situation, it's possible to define a lightweight Variable type, that will make the MVVM pattern very easy to use!

import Foundation

class Variable<Value> {
    var value: Value {
        didSet {
            onUpdate?(value)
        }
    }
    
    var onUpdate: ((Value) -> Void)? {
        didSet {
            onUpdate?(value)
        }
    }
    
    init(_ value: Value, _ onUpdate: ((Value) -> Void)? = nil) {
        self.value = value
        self.onUpdate = onUpdate
        self.onUpdate?(value)
    }
}

let variable: Variable<String?> = Variable(nil)

variable.onUpdate = { data in
    if let data = data {
        print(data)
    }
}

variable.value = "Foo"
variable.value = "Bar"

// prints:
// Foo
// Bar

Using typealias to its fullest

The keyword typealias allows developers to give a new name to an already existing type. For instance, Swift defines Void as a typealias of (), the empty tuple.

But a less known feature of this mechanism is that it allows to assign concrete types for generic parameters, or to rename them. This can help make the semantics of generic types much clearer, when used in specific use cases.

import Foundation

enum Either<Left, Right> {
    case left(Left)
    case right(Right)
}

typealias Result<Value> = Either<Value, Error>

typealias IntOrString = Either<Int, String>

Writing an interruptible overload of forEach

Iterating through objects via the forEach(_:) method is a great alternative to the classic for loop, as it allows our code to be completely oblivious of the iteration logic. One limitation, however, is that forEach(_:) does not allow to stop the iteration midway.

Taking inspiration from the Objective-C implementation, we can write an overload that will allow the developer to stop the iteration, if needed.

import Foundation

extension Sequence {
    func forEach(_ body: (Element, _ stop: inout Bool) throws -> Void) rethrows {
        var stop = false
        for element in self {
            try body(element, &stop)
            
            if stop {
                return
            }
        }
    }
}

["Foo", "Bar", "FooBar"].forEach { element, stop in
    print(element)
    stop = (element == "Bar")
}

// Prints:
// Foo
// Bar

Optimizing the use of reduce()

Functional programing is a great way to simplify a codebase. For instance, reduce is an alternative to the classic for loop, without most the boilerplate. Unfortunately, simplicity often comes at the price of performance.

Consider that you want to remove duplicate values from a Sequence. While reduce() is a perfectly fine way to express this computation, the performance will be sub optimal, because of all the unnecessary Array copying that will happen every time its closure gets called.

That's when reduce(into:_:) comes into play. This version of reduce leverages the capacities of copy-on-write type (such as Array or Dictionnary) in order to avoid unnecessary copying, which results in a great performance boost.

import Foundation

func time(averagedExecutions: Int = 1, _ code: () -> Void) {
    let start = Date()
    for _ in 0..<averagedExecutions { code() }
    let end = Date()
    
    let duration = end.timeIntervalSince(start) / Double(averagedExecutions)
    
    print("time: \(duration)")
}

let data = (1...1_000).map { _ in Int(arc4random_uniform(256)) }


// runs in 0.63s
time {
    let noDuplicates: [Int] = data.reduce([], { $0.contains($1) ? $0 : $0 + [$1] })
}

// runs in 0.15s
time {
    let noDuplicates: [Int] = data.reduce(into: [], { if !$0.contains($1) { $0.append($1) } } )
}

Avoiding hardcoded reuse identifiers

UI components such as UITableView and UICollectionView rely on reuse identifiers in order to efficiently recycle the views they display. Often, those reuse identifiers take the form of a static hardcoded String, that will be used for every instance of their class.

Through protocol-oriented programing, it's possible to avoid those hardcoded values, and instead use the name of the type as a reuse identifier.

import Foundation
import UIKit

protocol Reusable {
    static var reuseIdentifier: String { get }
}

extension Reusable {
    static var reuseIdentifier: String {
        return String(describing: self)
    }
}

extension UITableViewCell: Reusable { }

extension UITableView {
    func register<T: UITableViewCell>(_ class: T.Type) {
        register(`class`, forCellReuseIdentifier: T.reuseIdentifier)
    }
    func dequeueReusableCell<T: UITableViewCell>(for indexPath: IndexPath) -> T {
        return dequeueReusableCell(withIdentifier: T.reuseIdentifier, for: indexPath) as! T
    }
}

class MyCell: UITableViewCell { }

let tableView = UITableView()

tableView.register(MyCell.self)
let myCell: MyCell = tableView.dequeueReusableCell(for: [0, 0])

Defining a union type

The C language has a construct called union, that allows a single variable to hold values from different types. While Swift does not provide such a construct, it provides enums with associated values, which allows us to define a type called Either that implements a union of two types.

import Foundation

enum Either<A, B> {
    case left(A)
    case right(B)
    
    func either(ifLeft: ((A) -> Void)? = nil, ifRight: ((B) -> Void)? = nil) {
        switch self {
        case let .left(a):
            ifLeft?(a)
        case let .right(b):
            ifRight?(b)
        }
    }
}

extension Bool { static func random() -> Bool { return arc4random_uniform(2) == 0 } }

var intOrString: Either<Int, String> = Bool.random() ? .left(2) : .right("Foo")

intOrString.either(ifLeft: { print($0 + 1) }, ifRight: { print($0 + "Bar") })

If you're interested by this kind of data structure, I strongly recommend that you learn more about Algebraic Data Types.

Asserting that classes have associated NIBs and vice-versa

Most of the time, when we create a .xib file, we give it the same name as its associated class. From that, if we later refactor our code and rename such a class, we run the risk of forgetting to rename the associated .xib.

While the error will often be easy to catch, if the .xib is used in a remote section of its app, it might go unnoticed for sometime. Fortunately it's possible to build custom test predicates that will assert that 1) for a given class, there exists a .nib with the same name in a given Bundle, 2) for all the .nib in a given Bundle, there exists a class with the same name.

import XCTest

public func XCTAssertClassHasNib(_ class: AnyClass, bundle: Bundle, file: StaticString = #file, line: UInt = #line) {
    let associatedNibURL = bundle.url(forResource: String(describing: `class`), withExtension: "nib")
    
    XCTAssertNotNil(associatedNibURL, "Class \"\(`class`)\" has no associated nib file", file: file, line: line)
}

public func XCTAssertNibHaveClasses(_ bundle: Bundle, file: StaticString = #file, line: UInt = #line) {
    guard let bundleName = bundle.infoDictionary?["CFBundleName"] as? String,
        let basePath = bundle.resourcePath,
        let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: basePath),
                                                    includingPropertiesForKeys: nil,
                                                    options: [.skipsHiddenFiles, .skipsSubdirectoryDescendants]) else { return }
    
    var nibFilesURLs = [URL]()
    
    for case let fileURL as URL in enumerator {
        if fileURL.pathExtension.uppercased() == "NIB" {
            nibFilesURLs.append(fileURL)
        }
    }
    
    nibFilesURLs.map { $0.lastPathComponent }
        .compactMap { $0.split(separator: ".").first }
        .map { String($0) }
        .forEach {
            let associatedClass: AnyClass? = bundle.classNamed("\(bundleName).\($0)")
            
            XCTAssertNotNil(associatedClass, "File \"\($0).nib\" has no associated class", file: file, line: line)
        }
}

XCTAssertClassHasNib(MyFirstTableViewCell.self, bundle: Bundle(for: AppDelegate.self))
XCTAssertClassHasNib(MySecondTableViewCell.self, bundle: Bundle(for: AppDelegate.self))
        
XCTAssertNibHaveClasses(Bundle(for: AppDelegate.self))

Many thanks Benjamin Lavialle for coming up with the idea behind the second test predicate.

Small footprint type-erasing with functions

Seasoned Swift developers know it: a protocol with associated type (PAT) "can only be used as a generic constraint because it has Self or associated type requirements". When we really need to use a PAT to type a variable, the goto workaround is to use a type-erased wrapper.

While this solution works perfectly, it requires a fair amount of boilerplate code. In instances where we are only interested in exposing one particular function of the PAT, a shorter approach using function types is possible.

import Foundation
import UIKit

protocol Configurable {
    associatedtype Model
    
    func configure(with model: Model)
}

typealias Configurator<Model> = (Model) -> ()

extension UILabel: Configurable {
    func configure(with model: String) {
        self.text = model
    }
}

let label = UILabel()
let configurator: Configurator<String> = label.configure

configurator("Foo")

label.text // "Foo"

Performing animations sequentially

UIKit exposes a very powerful and simple API to perform view animations. However, this API can become a little bit quirky to use when we want to perform animations sequentially, because it involves nesting closure within one another, which produces notoriously hard to maintain code.

Nonetheless, it's possible to define a rather simple class, that will expose a really nicer API for this particular use case 👌

import Foundation
import UIKit

class AnimationSequence {
    typealias Animations = () -> Void
    
    private let current: Animations
    private let duration: TimeInterval
    private var next: AnimationSequence? = nil
    
    init(animations: @escaping Animations, duration: TimeInterval) {
        self.current = animations
        self.duration = duration
    }
    
    @discardableResult func append(animations: @escaping Animations, duration: TimeInterval) -> AnimationSequence {
        var lastAnimation = self
        while let nextAnimation = lastAnimation.next {
            lastAnimation = nextAnimation
        }
        lastAnimation.next = AnimationSequence(animations: animations, duration: duration)
        return self
    }
    
    func run() {
        UIView.animate(withDuration: duration, animations: current, completion: { finished in
            if finished, let next = self.next {
                next.run()
            }
        })
    }
}

var firstView = UIView()
var secondView = UIView()

firstView.alpha = 0
secondView.alpha = 0

AnimationSequence(animations: { firstView.alpha = 1.0 }, duration: 1)
            .append(animations: { secondView.alpha = 1.0 }, duration: 0.5)
            .append(animations: { firstView.alpha = 0.0 }, duration: 2.0)
            .run()

Debouncing a function call

Debouncing is a very useful tool when dealing with UI inputs. Consider a search bar, whose content is used to query an API. It wouldn't make sense to perform a request for every character the user is typing, because as soon as a new character is entered, the result of the previous request has become irrelevant.

Instead, our code will perform much better if we "debounce" the API call, meaning that we will wait until some delay has passed, without the input being modified, before actually performing the call.

import Foundation

func debounced(delay: TimeInterval, queue: DispatchQueue = .main, action: @escaping (() -> Void)) -> () -> Void {
    var workItem: DispatchWorkItem?
    
    return {
        workItem?.cancel()
        workItem = DispatchWorkItem(block: action)
        queue.asyncAfter(deadline: .now() + delay, execute: workItem!)
    }
}

let debouncedPrint = debounced(delay: 1.0) { print("Action performed!") }

debouncedPrint()
debouncedPrint()
debouncedPrint()

// After a 1 second delay, this gets
// printed only once to the console:

// Action performed!

Providing useful operators for Optional booleans

When we need to apply the standard boolean operators to Optional booleans, we often end up with a syntax unnecessarily crowded with unwrapping operations. By taking a cue from the world of three-valued logics, we can define a couple operators that make working with Bool? values much nicer.

import Foundation

func && (lhs: Bool?, rhs: Bool?) -> Bool? {
    switch (lhs, rhs) {
    case (false, _), (_, false):
        return false
    case let (unwrapLhs?, unwrapRhs?):
        return unwrapLhs && unwrapRhs
    default:
        return nil
    }
}

func || (lhs: Bool?, rhs: Bool?) -> Bool? {
    switch (lhs, rhs) {
    case (true, _), (_, true):
        return true
    case let (unwrapLhs?, unwrapRhs?):
        return unwrapLhs || unwrapRhs
    default:
        return nil
    }
}

false && nil // false
true && nil // nil
[true, nil, false].reduce(true, &&) // false

nil || true // true
nil || false // nil
[true, nil, false].reduce(false, ||) // true

Removing duplicate values from a Sequence

Transforming a Sequence in order to remove all the duplicate values it contains is a classic use case. To implement it, one could be tempted to transform the Sequence into a Set, then back to an Array. The downside with this approach is that it will not preserve the order of the sequence, which can definitely be a dealbreaker. Using reduce() it is possible to provide a concise implementation that preserves ordering:

import Foundation

extension Sequence where Element: Equatable {
    func duplicatesRemoved() -> [Element] {
        return reduce([], { $0.contains($1) ? $0 : $0 + [$1] })
    }
}

let data = [2, 5, 2, 3, 6, 5, 2]

data.duplicatesRemoved() // [2, 5, 3, 6]

Shorter syntax to deal with optional strings

Optional strings are very common in Swift code, for instance many objects from UIKit expose the text they display as a String?. Many times you will need to manipulate this data as an unwrapped String, with a default value set to the empty string for nil cases.

While the nil-coalescing operator (e.g. ??) is a perfectly fine way to a achieve this goal, defining a computed variable like orEmpty can help a lot in cleaning the syntax.

import Foundation
import UIKit

extension Optional where Wrapped == String {
    var orEmpty: String {
        switch self {
        case .some(let value):
            return value
        case .none:
            return ""
        }
    }
}

func doesNotWorkWithOptionalString(_ param: String) {
    // do something with `param`
}

let label = UILabel()
label.text = "This is some text."

doesNotWorkWithOptionalString(label.text.orEmpty)

Encapsulating background computation and UI update

Every seasoned iOS developers knows it: objects from UIKit can only be accessed from the main thread. Any attempt to access them from a background thread is a guaranteed crash.

Still, running a costly computation on the background, and then using it to update the UI can be a common pattern.

In such cases you can rely on asyncUI to encapsulate all the boilerplate code.

import Foundation
import UIKit

func asyncUI<T>(_ computation: @autoclosure @escaping () -> T, qos: DispatchQoS.QoSClass = .userInitiated, _ completion: @escaping (T) -> Void) {
    DispatchQueue.global(qos: qos).async {
        let value = computation()
        DispatchQueue.main.async {
            completion(value)
        }
    }
}

let label = UILabel()

func costlyComputation() -> Int { return (0..<10_000).reduce(0, +) }

asyncUI(costlyComputation()) { value in
    label.text = "\(value)"
}

Retrieving all the necessary data to build a debug view

A debug view, from which any controller of an app can be instantiated and pushed on the navigation stack, has the potential to bring some real value to a development process. A requirement to build such a view is to have a list of all the classes from a given Bundle that inherit from UIViewController. With the following extension, retrieving this list becomes a piece of cake 🍰

import Foundation
import UIKit
import ObjectiveC

extension Bundle {
    func viewControllerTypes() -> [UIViewController.Type] {
        guard let bundlePath = self.executablePath else { return [] }
        
        var size: UInt32 = 0
        var rawClassNames: UnsafeMutablePointer<UnsafePointer<Int8>>!
        var parsedClassNames = [String]()
        
        rawClassNames = objc_copyClassNamesForImage(bundlePath, &size)
        
        for index in 0..<size {
            let className = rawClassNames[Int(index)]
            
            if let name = NSString.init(utf8String:className) as String?,
                NSClassFromString(name) is UIViewController.Type {
                parsedClassNames.append(name)
            }
        }
        
        return parsedClassNames
            .sorted()
            .compactMap { NSClassFromString($0) as? UIViewController.Type }
    }
}

// Fetch all view controller types in UIKit
Bundle(for: UIViewController.self).viewControllerTypes()

I share the credit for this tip with Benoît Caron.

Defining a function to map over dictionaries

Update As it turns out, map is actually a really bad name for this function, because it does not preserve composition of transformations, a property that is required to fit the definition of a real map function.

Surprisingly enough, the standard library doesn't define a map() function for dictionaries that allows to map both keys and values into a new Dictionary. Nevertheless, such a function can be helpful, for instance when converting data across different frameworks.

import Foundation

extension Dictionary {
    func map<T: Hashable, U>(_ transform: (Key, Value) throws -> (T, U)) rethrows -> [T: U] {
        var result: [T: U] = [:]
        
        for (key, value) in self {
            let (transformedKey, transformedValue) = try transform(key, value)
            result[transformedKey] = transformedValue
        }
        
        return result
    }
}

let data = [0: 5, 1: 6, 2: 7]
data.map { ("\($0)", $1 * $1) } // ["2": 49, "0": 25, "1": 36]

A shorter syntax to remove nil values

Swift provides the function compactMap(), that can be used to remove nil values from a Sequence of optionals when calling it with an argument that just returns its parameter (i.e. compactMap { $0 }). Still, for such use cases it would be nice to get rid of the trailing closure.

The implementation isn't as straightforward as your usual extension, but once it has been written, the call site definitely gets cleaner 👌

import Foundation

protocol OptionalConvertible {
    associatedtype Wrapped
    func asOptional() -> Wrapped?
}

extension Optional: OptionalConvertible {
    func asOptional() -> Wrapped? {
        return self
    }
}

extension Sequence where Element: OptionalConvertible {
    func compacted() -> [Element.Wrapped] {
        return compactMap { $0.asOptional() }
    }
}

let data = [nil, 1, 2, nil, 3, 5, nil, 8, nil]
data.compacted() // [1, 2, 3, 5, 8]

Dealing with expirable values

It might happen that your code has to deal with values that come with an expiration date. In a game, it could be a score multiplier that will only last for 30 seconds. Or it could be an authentication token for an API, with a 15 minutes lifespan. In both instances you can rely on the type Expirable to encapsulate the expiration logic.

import Foundation

struct Expirable<T> {
    private var innerValue: T
    private(set) var expirationDate: Date
    
    var value: T? {
        return hasExpired() ? nil : innerValue
    }
    
    init(value: T, expirationDate: Date) {
        self.innerValue = value
        self.expirationDate = expirationDate
    }
    
    init(value: T, duration: Double) {
        self.innerValue = value
        self.expirationDate = Date().addingTimeInterval(duration)
    }
    
    func hasExpired() -> Bool {
        return expirationDate < Date()
    }
}

let expirable = Expirable(value: 42, duration: 3)

sleep(2)
expirable.value // 42
sleep(2)
expirable.value // nil

I share the credit for this tip with Benoît Caron.

Using parallelism to speed-up map()

Almost all Apple devices able to run Swift code are powered by a multi-core CPU, consequently making a good use of parallelism is a great way to improve code performance. map() is a perfect candidate for such an optimization, because it is almost trivial to define a parallel implementation.

import Foundation

extension Array {
    func parallelMap<T>(_ transform: (Element) -> T) -> [T] {
        let res = UnsafeMutablePointer<T>.allocate(capacity: count)
        
        DispatchQueue.concurrentPerform(iterations: count) { i in
            res[i] = transform(self[i])
        }
        
        let finalResult = Array<T>(UnsafeBufferPointer(start: res, count: count))
        res.deallocate(capacity: count)
        
        return finalResult
    }
}

let array = (0..<1_000).map { $0 }

func work(_ n: Int) -> Int {
    return (0..<n).reduce(0, +)
}

array.parallelMap { work($0) }

🚨 Make sure to only use parallelMap() when the transform function actually performs some costly computations. Otherwise performances will be systematically slower than using map(), because of the multithreading overhead.

Measuring execution time with minimum boilerplate

During development of a feature that performs some heavy computations, it can be helpful to measure just how much time a chunk of code takes to run. The time() function is a nice tool for this purpose, because of how simple it is to add and then to remove when it is no longer needed.

import Foundation

func time(averagedExecutions: Int = 1, _ code: () -> Void) {
    let start = Date()
    for _ in 0..<averagedExecutions { code() }
    let end = Date()
    
    let duration = end.timeIntervalSince(start) / Double(averagedExecutions)
    
    print("time: \(duration)")
}

time {
    (0...10_000).map { $0 * $0 }
}
// time: 0.183973908424377

Running two pieces of code in parallel

Concurrency is definitely one of those topics were the right encapsulation bears the potential to make your life so much easier. For instance, with this piece of code you can easily launch two computations in parallel, and have the results returned in a tuple.

import Foundation

func parallel<T, U>(_ left: @autoclosure () -> T, _ right: @autoclosure () -> U) -> (T, U) {
    var leftRes: T?
    var rightRes: U?
    
    DispatchQueue.concurrentPerform(iterations: 2, execute: { id in
        if id == 0 {
            leftRes = left()
        } else {
            rightRes = right()
        }
    })
    
    return (leftRes!, rightRes!)
}

let values = (1...100_000).map { $0 }

let results = parallel(values.map { $0 * $0 }, values.reduce(0, +))

Making good use of #file, #line and #function

Swift exposes three special variables #file, #line and #function, that are respectively set to the name of the current file, line and function. Those variables become very useful when writing custom logging functions or test predicates.

import Foundation

func log(_ message: String, _ file: String = #file, _ line: Int = #line, _ function: String = #function) {
    print("[\(file):\(line)] \(function) - \(message)")
}

func foo() {
    log("Hello world!")
}

foo() // [MyPlayground.playground:8] foo() - Hello world!

Comparing Optionals through Conditional Conformance

Swift 4.1 has introduced a new feature called Conditional Conformance, which allows a type to implement a protocol only when its generic type also does.

With this addition it becomes easy to let Optional implement Comparable only when Wrapped also implements Comparable:

import Foundation

extension Optional: Comparable where Wrapped: Comparable {
    public static func < (lhs: Optional, rhs: Optional) -> Bool {
        switch (lhs, rhs) {
        case let (lhs?, rhs?):
            return lhs < rhs
        case (nil, _?):
            return true // anything is greater than nil
        case (_?, nil):
            return false // nil in smaller than anything
        case (nil, nil):
            return true // nil is not smaller than itself
        }
    }
}

let data: [Int?] = [8, 4, 3, nil, 12, 4, 2, nil, -5]
data.sorted() // [nil, nil, Optional(-5), Optional(2), Optional(3), Optional(4), Optional(4), Optional(8), Optional(12)]

Safely subscripting a Collection

Any attempt to access an Array beyond its bounds will result in a crash. While it's possible to write conditions such as if index < array.count { array[index] } in order to prevent such crashes, this approach will rapidly become cumbersome.

A great thing is that this condition can be encapsulated in a custom subscript that will work on any Collection:

import Foundation

extension Collection {
    subscript (safe index: Index) -> Element? {
        return indices.contains(index) ? self[index] : nil
    }
}

let data = [1, 3, 4]

data[safe: 1] // Optional(3)
data[safe: 10] // nil

Easier String slicing using ranges

Subscripting a string with a range can be very cumbersome in Swift 4. Let's face it, no one wants to write lines like someString[index(startIndex, offsetBy: 0)..<index(startIndex, offsetBy: 10)] on a regular basis.

Luckily, with the addition of one clever extension, strings can be sliced as easily as arrays 🎉

import Foundation

extension String {
    public subscript(value: CountableClosedRange<Int>) -> Substring {
        get {
            return self[index(startIndex, offsetBy: value.lowerBound)...index(startIndex, offsetBy: value.upperBound)]
        }
    }
    
    public subscript(value: CountableRange<Int>) -> Substring {
        get {
            return self[index(startIndex, offsetBy: value.lowerBound)..<index(startIndex, offsetBy: value.upperBound)]
        }
    }
    
    public subscript(value: PartialRangeUpTo<Int>) -> Substring {
        get {
            return self[..<index(startIndex, offsetBy: value.upperBound)]
        }
    }
    
    public subscript(value: PartialRangeThrough<Int>) -> Substring {
        get {
            return self[...index(startIndex, offsetBy: value.upperBound)]
        }
    }
    
    public subscript(value: PartialRangeFrom<Int>) -> Substring {
        get {
            return self[index(startIndex, offsetBy: value.lowerBound)...]
        }
    }
}

let data = "This is a string!"

data[..<4]  // "This"
data[5..<9] // "is a"
data[10...] // "string!"

Concise syntax for sorting using a KeyPath

By using a KeyPath along with a generic type, a very clean and concise syntax for sorting data can be implemented:

import Foundation

extension Sequence {
    func sorted<T: Comparable>(by attribute: KeyPath<Element, T>) -> [Element] {
        return sorted(by: { $0[keyPath: attribute] < $1[keyPath: attribute] })
    }
}

let data = ["Some", "words", "of", "different", "lengths"]

data.sorted(by: \.count) // ["of", "Some", "words", "lengths", "different"]

If you like this syntax, make sure to checkout KeyPathKit!

Manufacturing cache-efficient versions of pure functions

By capturing a local variable in a returned closure, it is possible to manufacture cache-efficient versions of pure functions. Be careful though, this trick only works with non-recursive function!

import Foundation

func cached<In: Hashable, Out>(_ f: @escaping (In) -> Out) -> (In) -> Out {
    var cache = [In: Out]()
    
    return { (input: In) -> Out in
        if let cachedValue = cache[input] {
            return cachedValue
        } else {
            let result = f(input)
            cache[input] = result
            return result
        }
    }
}

let cachedCos = cached { (x: Double) in cos(x) }

cachedCos(.pi * 2) // value of cos for 2π is now cached

Simplifying complex conditions with pattern matching

When distinguishing between complex boolean conditions, using a switch statement along with pattern matching can be more readable than the classic series of if {} else if {}.

import Foundation

let expr1: Bool
let expr2: Bool
let expr3: Bool

if expr1 && !expr3 {
    functionA()
} else if !expr2 && expr3 {
    functionB()
} else if expr1 && !expr2 && expr3 {
    functionC()
}

switch (expr1, expr2, expr3) {
    
case (true, _, false):
    functionA()
case (_, false, true):
    functionB()
case (true, false, true):
    functionC()
default:
    break
}

Easily generating arrays of data

Using map() on a range makes it easy to generate an array of data.

import Foundation

func randomInt() -> Int { return Int(arc4random()) }

let randomArray = (1...10).map { _ in randomInt() }

Using @autoclosure for cleaner call sites

Using @autoclosure enables the compiler to automatically wrap an argument within a closure, thus allowing for a very clean syntax at call sites.

import UIKit

extension UIView {
    class func animate(withDuration duration: TimeInterval, _ animations: @escaping @autoclosure () -> Void) {
        UIView.animate(withDuration: duration, animations: animations)
    }
}

let view = UIView()

UIView.animate(withDuration: 0.3, view.backgroundColor = .orange)

Observing new and old value with RxSwift

When working with RxSwift, it's very easy to observe both the current and previous value of an observable sequence by simply introducing a shift using skip().

import RxSwift

let values = Observable.of(4, 8, 15, 16, 23, 42)

let newAndOld = Observable.zip(values, values.skip(1)) { (previous: $0, current: $1) }
    .subscribe(onNext: { pair in
        print("current: \(pair.current) - previous: \(pair.previous)")
    })

//current: 8 - previous: 4
//current: 15 - previous: 8
//current: 16 - previous: 15
//current: 23 - previous: 16
//current: 42 - previous: 23

Implicit initialization from literal values

Using protocols such as ExpressibleByStringLiteral it is possible to provide an init that will be automatically when a literal value is provided, allowing for nice and short syntax. This can be very helpful when writing mock or test data.

import Foundation

extension URL: ExpressibleByStringLiteral {
    public init(stringLiteral value: String) {
        self.init(string: value)!
    }
}

let url: URL = "http://www.google.fr"

NSURLConnection.canHandle(URLRequest(url: "http://www.google.fr"))

Achieving systematic validation of data

Through some clever use of Swift private visibility it is possible to define a container that holds any untrusted value (such as a user input) from which the only way to retrieve the value is by making it successfully pass a validation test.

import Foundation

struct Untrusted<T> {
    private(set) var value: T
}

protocol Validator {
    associatedtype T
    static func validation(value: T) -> Bool
}

extension Validator {
    static func validate(untrusted: Untrusted<T>) -> T? {
        if self.validation(value: untrusted.value) {
            return untrusted.value
        } else {
            return nil
        }
    }
}

struct FrenchPhoneNumberValidator: Validator {
    static func validation(value: String) -> Bool {
       return (value.count) == 10 && CharacterSet(charactersIn: value).isSubset(of: CharacterSet.decimalDigits)
    }
}

let validInput = Untrusted(value: "0122334455")
let invalidInput = Untrusted(value: "0123")

FrenchPhoneNumberValidator.validate(untrusted: validInput) // returns "0122334455"
FrenchPhoneNumberValidator.validate(untrusted: invalidInput) // returns nil

Implementing the builder pattern with keypaths

With the addition of keypaths in Swift 4, it is now possible to easily implement the builder pattern, that allows the developer to clearly separate the code that initializes a value from the code that uses it, without the burden of defining a factory method.

import UIKit

protocol With {}

extension With where Self: AnyObject {
    @discardableResult
    func with<T>(_ property: ReferenceWritableKeyPath<Self, T>, setTo value: T) -> Self {
        self[keyPath: property] = value
        return self
    }
}

extension UIView: With {}

let view = UIView()

let label = UILabel()
    .with(\.textColor, setTo: .red)
    .with(\.text, setTo: "Foo")
    .with(\.textAlignment, setTo: .right)
    .with(\.layer.cornerRadius, setTo: 5)

view.addSubview(label)

🚨 The Swift compiler does not perform OS availability checks on properties referenced by keypaths. Any attempt to use a KeyPath for an unavailable property will result in a runtime crash.

I share the credit for this tip with Marion Curtil.

Storing functions rather than values

When a type stores values for the sole purpose of parametrizing its functions, it’s then possible to not store the values but directly the function, with no discernable difference at the call site.

import Foundation

struct MaxValidator {
    let max: Int
    let strictComparison: Bool
    
    func isValid(_ value: Int) -> Bool {
        return self.strictComparison ? value < self.max : value <= self.max
    }
}

struct MaxValidator2 {
    var isValid: (_ value: Int) -> Bool
    
    init(max: Int, strictComparison: Bool) {
        self.isValid = strictComparison ? { $0 < max } : { $0 <= max }
    }
}

MaxValidator(max: 5, strictComparison: true).isValid(5) // false
MaxValidator2(max: 5, strictComparison: false).isValid(5) // true

Defining operators on function types

Functions are first-class citizen types in Swift, so it is perfectly legal to define operators for them.

import Foundation

let firstRange = { (0...3).contains($0) }
let secondRange = { (5...6).contains($0) }

func ||(_ lhs: @escaping (Int) -> Bool, _ rhs: @escaping (Int) -> Bool) -> (Int) -> Bool {
    return { value in
        return lhs(value) || rhs(value)
    }
}

(firstRange || secondRange)(2) // true
(firstRange || secondRange)(4) // false
(firstRange || secondRange)(6) // true

Typealiases for functions

Typealiases are great to express function signatures in a more comprehensive manner, which then enables us to easily define functions that operate on them, resulting in a nice way to write and use some powerful API.

import Foundation

typealias RangeSet = (Int) -> Bool

func union(_ left: @escaping RangeSet, _ right: @escaping RangeSet) -> RangeSet {
    return { left($0) || right($0) }
}

let firstRange = { (0...3).contains($0) }
let secondRange = { (5...6).contains($0) }

let unionRange = union(firstRange, secondRange)

unionRange(2) // true
unionRange(4) // false

Encapsulating state within a function

By returning a closure that captures a local variable, it's possible to encapsulate a mutable state within a function.

import Foundation

func counterFactory() -> () -> Int {
    var counter = 0
    
    return {
        counter += 1
        return counter
    }
}

let counter = counterFactory()

counter() // returns 1
counter() // returns 2

Generating all cases for an Enum

⚠️ Since Swift 4.2, allCases can now be synthesized at compile-time by simply conforming to the protocol CaseIterable. The implementation below should no longer be used in production code.

Through some clever leveraging of how enums are stored in memory, it is possible to generate an array that contains all the possible cases of an enum. This can prove particularly useful when writing unit tests that consume random data.

import Foundation

enum MyEnum { case first; case second; case third; case fourth }

protocol EnumCollection: Hashable {
    static var allCases: [Self] { get }
}

extension EnumCollection {
    public static var allCases: [Self] {
        var i = 0
        return Array(AnyIterator {
            let next = withUnsafePointer(to: &i) {
                $0.withMemoryRebound(to: Self.self, capacity: 1) { $0.pointee }
            }
            if next.hashValue != i { return nil }
            i += 1
            return next
        })
    }
}

extension MyEnum: EnumCollection { }

MyEnum.allCases // [.first, .second, .third, .fourth]

Using map on optional values

The if-let syntax is a great way to deal with optional values in a safe manner, but at times it can prove to be just a little bit to cumbersome. In such cases, using the Optional.map() function is a nice way to achieve a shorter code while retaining safeness and readability.

import UIKit

let date: Date? = Date() // or could be nil, doesn't matter
let formatter = DateFormatter()
let label = UILabel()

if let safeDate = date {
    label.text = formatter.string(from: safeDate)
}

label.text = date.map { return formatter.string(from: $0) }

label.text = date.map(formatter.string(from:)) // even shorter, tough less readable

Download Details:

Author: Vincent-pradeilles
Source Code: https://github.com/vincent-pradeilles/swift-tips 
License: MIT license

#swift #tips 

Swift-tips: A Collection Useful Tips for The Swift Language