You are here

سیاره‌ی مشهدلاگ

گرفتن زیرشاخه‌های خاص از یک مخزن Git

routes - Fri, 08/01/2014 - 14:29

نوشته از Jason Karns در Code Nomad

ممکنه یک زمانی بخواهید از یک مخزن Git فقط یک قسمت/پوشه خاص رو دریافت کنین و آپدیت نگه‌اش دارین. برای اینکار باید از امکان spare-checkout گیت استفاده کنید.

مخزن جدید

برای اینکه بشه از این امکان استفاده کرد، باید تو تنظیمات مخزن گیت core.sparecheckout مقدار true تظیم بشه. برای اینکار هم لازمه‌اش اینه که مخزن از قبل وجود داشته باشه. پس به جای اینکه git clone کرد، باید git init انجام داد.

مخزن جدید رو بسازید:

mkdir <repo> && cd <repo>
git init
git remote add –f <name> <url>

امکان spare-checkout رو فعال کنید:

git config core.sparsecheckout true

زیر شاخه‌هایی که میخواین رو در .git/info/spare-checkout اضافه کنید:

echo some/dir/ >> .git/info/sparse-checkout
echo another/sub/tree >> .git/info/sparse-checkout

حالا مخزن رو از سرور pull کنید:

git pull <remote> <branch>
مخزن موجود

اگر از قبل یک مخزن دارید و میخواید spare-checkout استفاده کنید، مثل مورد بالا spare-checkout رو فعال کنین و بعد هم git read-tree رو انجام بدین:

git config core.sparsecheckout true

اضافه کردن شاخه‌های مورد نیاز به .git/info/spare-checkout :

echo some/dir/ >> .git/info/sparse-checkout
echo another/sub/tree >> .git/info/sparse-checkout

مخزن رو آپدیت کنین:

git read-tree -mu HEAD
تغییر زیرشاخه‌های انتخاب شده

اگر بعداً تصمیم گرفتین که زیرشاخه‌هایی که انتخاب کردین رو تغییر بدین، خیلی راحت پرونده spare-checkout رو تغییر بدین و بعد هم git read-tree رو دوباره اجرا کنین.

مستندات مربوط به sub-tree/spare-checkout رو بخونید. پرونده spare-tree از الگوها هم پشتیبانی می‌کنه، دقیقا مثل gitignore. از لیست سیاه هم پشتیبانی میشه - میتونید انتخاب کنید که چه شاخه‌ها یا پرونده‌های checkout نشن.

شروع کار با Gulp

routes - Wed, 07/30/2014 - 16:51

نوشته از Mark Goodyear از اینجا

اگر روبی کار باشید، احتمالا با Guard آشنا هستین. به طور خلاصه Gulp همون Guard دنیای جاوا اسکریپت است. Gulp سیاست کد-دربرابر-پیکربندی داره. ینی برخلاف Grunt که برای تنظیم باید از کلیدهای پیش‌فرض خودش استفاده کنید و پیکربندی‌اش کنید، Gulp در واقع همون کد زدن برای node.js هست. بنابراین میشه از همه کتابخانه‌های npm در فایل تنظیمات Gulp استفاده کرد.

Gulp از استریم‌های node.js استفاده میکنه که باعث میشه buildها سریع‌تر ساخته بشن و برای ساخت اونها احتیاجی به ایجاد پرونده‌ها و پوشه‌های موقت نیست. اگر می‌خواهید بیشتر در مورد استریم‌های بدونید - با اینکه احتیاجی نیست - میتونید این مقاله رو بخونید. Gulp، برعکس Grunt که باید پیکربندی هر پلاگین رو بهش بدید، به شما اجازه میده که پرونده‌های پروژه‌تون رو بهش بدید، Gulp از طریق pipeها اونها رو از پلاگین‌هاش عبور میده و خروجی رو در نهایت به شما ارائه میکنه. بزارید یک مثال برای ساخت پرنده Sass در هر دو ابزار Grunt و Gulp رو ببینیم تا تفاوتشون بیشتر درک بشه:

Grunt
sass: {
  dist: {
    options: {
      style: 'expanded'
    },
    files: {
      'dist/assets/css/main.css': 'src/styles/main.scss',
    }
  }
},

autoprefixer: {
  dist: {
    options: {
      browsers: [
        'last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'
      ]
    },
    src: 'dist/assets/css/main.css',
    dest: 'dist/assets/css/main.css'
  }
},

grunt.registerTask('styles', ['sass', 'autoprefixer']);

برای Gulp باید هر پلاگین رو جداگانه پیکربندی کنید، پرونده‌های ورودی و محل خروجی رو هم براش مشخص کنید. برای مثال، ما اول باید یک پرونده ورودی رو به پلاگین Sass بدیم، که بعد پرنده خروجی رو برمیگردونه. بعد از اون باید خروجی پلاگین Sass رو به پلاگین Autoprefixer بدیم، که یک فایل دیگه رو به خروجی میده. حالا همین کار رو با Gulp انجام میدیم:

Gulp
gulp.task('sass', function() {
  return gulp.src('src/styles/main.scss')
    .pipe(sass({ style: 'compressed' }))
    .pipe(autoprefixer('last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'))
    .pipe(gulp.dest('dist/assets/css'))
});

با Gulp ما یکبار پرونده رو بهش میدیم. این پرونده توسط پلاگین Sass تغییر داده میشه، بعد پلاگین Autoprefixer ارسال میشه و تغییر داده میشه و در نهایت یک پرونده خارج میشه. این پروسه سرعت ساخت پرونده نهایی رو بیشتر میکنه، چون احتیاجی به ساخت پرونده‌های موقت مختلف برای تولید یک پرونده نهایی نیست.

خب. حالا که فهمیدیم Gulp چقدر خوب‌تره، نصبش می‌کنیم و چندتا کار مختلف باهاش انجام میدیم.

نصب Gulp

برای نصب عبارت زیر رو تو ترمینال وارد کنید. ممکنه احتیاج باشه sudo رو هم وارد کنید:

$ npm install gulp -g

این باعث میشه دسترسی به فرمان gulp رو در همه جای سیستم داشته باشیم. بعد از این Gulp باید به شکل محلی در مکان پروژه هم نصب بشه. cd کنید در محل پروژه و فرمان زیر رو اجرا کنید (مطمئن بشید که یک پرونده package.jsonدارید):

$ npm install gulp --save-dev

این فرمان Gulp رو به صورت محلی در پروژه شما نصب میکنه و اون رو در devDependencies در پرونده package.json اضافه میکنه.

نصب پلاگین‌های Gulp

ما تعدادی پلاگین برای انجام کارهای زیر رو نصب می‌کنیم:

برای نصب این پلاگین‌ها فرمان زیر رو بزنید:

$ npm install gulp-ruby-sass gulp-autoprefixer gulp-minify-css gulp-jshint gulp-concat gulp-uglify gulp-imagemin gulp-clean gulp-notify gulp-rename gulp-livereload gulp-cache --save-dev

این فرمان تمام پلاگین‌های مورد نیاز رو نصب و بد هم در قسمت devDependencies پرونده package.json اضافه می‌کنه. فهرست کامل پلاگین‌های Gulp رو می‌تونید اینجا ببینید.

بارگیری پلاگین‌ها

بعد از این لازم هست که یک پرونده gulpfile.js بسازیم و پلاگین‌هامون رو بهش معرفی کنیم:

var gulp = require('gulp'),
    sass = require('gulp-ruby-sass'),
    autoprefixer = require('gulp-autoprefixer'),
    minifycss = require('gulp-minify-css'),
    jshint = require('gulp-jshint'),
    uglify = require('gulp-uglify'),
    imagemin = require('gulp-imagemin'),
    rename = require('gulp-rename'),
    clean = require('gulp-clean'),
    concat = require('gulp-concat'),
    notify = require('gulp-notify'),
    cache = require('gulp-cache'),
    livereload = require('gulp-livereload');

پلاگین‌های Gulp متفاوت از پلاگین‌های Grunt هستن. اونها طوری نوشته شدن که فقط یک کار انجام بدن و اون کار رو درست و خوب انجام بدن (سیاست برنامه‌های گنو/لینوکسی هست درواقع اینجا :دی). مثلا، imagemin در Grunt از کش کردن برای فشرده نکردن عکس‌هایی که قبلا فشرده شدن استفاده میکنه. با Gulp، اینکار با یک پلاگین cache انجا میشه، که میشه برای کش کردن چیزهای دیگه هم ازش استفاده کرد. این کار انعطاف‌پذیری بیشتری به پروسه ساخت میده.

میشه پلاگین‌ها رو خودکار بارگیری کرد، اما برای این پست ما به همین روش دستی قناعت می‌کنیم!

ساخت وظیفه‌ها (Task) کامپایل پرونده Sass، استفاده از Autoprefix و کوچک کردن پرونده‌ها

اول از همه، ما کامپایل Sass رو پیکربندی می‌کنیم. ما پرونده Sass رو به شکل expanded کامپایل می‌کنیم، بعد می‌فرستیمش برای Autoprefixer و در محل مورد نظرمون قرارش می‌دیم. بعد از اون یک نسخه .min هم ازش می‌سازیم، صفحه مرورگر رو به طور خودکار دوباره بارگیری می‌کنیم بعد هم یک اعلان به ما خبر میده که کار Gulp تموم شده:

gulp.task('styles', function() {
  return gulp.src('src/styles/main.scss')
    .pipe(sass({ style: 'expanded' }))
    .pipe(autoprefixer('last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'))
    .pipe(gulp.dest('dist/assets/css'))
    .pipe(rename({suffix: '.min'}))
    .pipe(minifycss())
    .pipe(gulp.dest('dist/assets/css'))
    .pipe(notify({ message: 'Styles task complete' }));
});

کمی توضیحات بیشتر، قبل از اینکه ادامه بدیم.

gulp.task('styles', function() { ... )};

این API مربوط به gulp.task هست که برای ساخت هر وظیفه مختلف Gulp استفاده میشه. وظیفه‌ای که بالا ساختیم رو می‌تونیم با عبارت $ gulp styles اجرا کنیم.

return gulp.src('src/styles/main.scss')

سینتکس مربوط به gulp.src که پرونده‌های ورودی رو باهاش مشخص می‌کنیم. ورودی این قسمت می‌تونه یک الگو کلی مثل /**/*.scss باشه. با برگردوندن (return) استریم، وظیفه‌ای که تعریف کردیم asynchronous میشه و مطمئن میشیم که وظیفه قبل از اعلانِ پیامِ اتمام، تمام کارها رو کامل انجام داده.

.pipe(sass({ style: 'expanded' }))

ما از .pipe() برای انتقال پرونده‌ها به پلاگین‌ها استفاده می‌کنیم. معمولا گزینه‌های مربوط به هر پلاگین رو میتونید صفحه گیت‌هابشون ببینید. من لینک‌های اونها رو بالا براتون گذاشتم.

.pipe(gulp.dest('dist/assets/css'));

سینتکس بالا مربوط به gulp.dest است که آدرس خروجی رو بهش میدیم. هر وظیفه می‌تونه تعدادی بیشتر از یک دونه خروجی داشته باشه. مثلا یک خروجی پرونده expanded رو ذخیره می‌کنه و خروجی دیگه پرونده خلاصه شده. این کار رو ما در مثال بالا انجام دادیم.

من پیشنهاد می‌کنم مستندات API مربوط به Gulp رو بخونید تا درک بهتری از API داشته باشین. اونقدری که به نظر میاد ترسناک نیست!

استفاده از JSHint و concat و خلاصه کردن جاوااسکریپت

احتمالا تا الان نحوه نوشتن یک وظیفه برای Gulp رو یاد گرفتین. در ادامه، ما کدها رو برای lint و concat و همچنین uglify اضافه می‌کنیم:

gulp.task('scripts', function() {
  return gulp.src('src/scripts/**/*.js')
    .pipe(jshint('.jshintrc'))
    .pipe(jshint.reporter('default'))
    .pipe(concat('main.js'))
    .pipe(gulp.dest('dist/assets/js'))
    .pipe(rename({suffix: '.min'}))
    .pipe(uglify())
    .pipe(gulp.dest('dist/assets/js'))
    .pipe(notify({ message: 'Scripts task complete' }));
});

یک نکته اینکه ما باید برای JSHint از یک گزارشگر استفاده کنیم. من از همون گزارشگر پیش‌فرض استفاده می‌کنم که احتمالا برای اکثر توسعه‌دهنده‌ها کافی است. اطلاعات بیشتر رو می‌تونید تو سایت JSHint ببینید.

فشرده کردن عکس‌ها

در ادامه، فشرده‌سازی عکس‌ها رو انجام می‌دیم:

gulp.task('images', function() {
  return gulp.src('src/images/**/*')
    .pipe(imagemin({ optimizationLevel: 3, progressive: true, interlaced: true }))
    .pipe(gulp.dest('dist/assets/img'))
    .pipe(notify({ message: 'Images task complete' }));
});

این کد تمام عکس‌ها رو میگیره و بعد میفرسته برای پلاگین imagemin. میشه بیشتر ادامه داد و از امکان کش کردن برای اینکه عکس‌های فشرده شده رو دوباره فشرده‌سازی نکنیم، استفاده کرد. برای اینکار فقط به پلاگین gulp-cache احتیاج داریم - که قبلا نصبش کردیم. برای اینکار باید خط زیر رو:

.pipe(imagemin({ optimizationLevel: 3, progressive: true, interlaced: true }))

به شکل زیر اصلاح کنیم:

.pipe(cache(imagemin({ optimizationLevel: 5, progressive: true, interlaced: true })))

حالا فقط عکس‌هایی که فشرده نشدن یا جدید هستن فشرده میشن. باحاله!

تمیزکاری!

قبل از فرستادن پروژه به سرور، بهتره که پوشه‌های مقصدمون رو تمیز کنیم و پرونده‌ها رو دوباره بسازیم - برای اینکه مطمئن بشیم که پرونده‌هایی که ممکنه از سورس اصلی حذف کردیم، نسخه ساخته شدشون تو پوشه مقصد نباشه هنوز:

gulp.task('clean', function() {
  return gulp.src(['dist/assets/css', 'dist/assets/js', 'dist/assets/img'], {read: false})
    .pipe(clean());
});

ما حتی می‌تونیم یک آرایه از پوشه‌ها (یا پرونده‌ها) رو به gulp.src بدیم. با توجه به اینکه احتیاجی نیست پرونده‌هایی که حذف شدن رو بخونیم، میتونیم read: false رو به گزینه‌ها اضافه کنیم تا به Gulp بگیم احتیاجی به خوندن محتویات پرونده‌ها نیست - کمی سرعتش بیشتر میشه.

تعریف وظیفه پیش‌فرض

می‌تونیم یک وظیفه پیش‌فرض اضافه کنیم تا وقتی دستور $ gulp رو میزنیم اجرا بشه و هر سه وظیفه‌ای که برای Gulp تعریف کردیم رو اجرا کنه:

gulp.task('default', ['clean'], function() {
    gulp.start('styles', 'scripts', 'images');
});

به آرایه‌ای که به gulp.task اضافه شدن دقت کنین. اینجا جایی هست که می‌تونیم وابستگی‌های این وظیفه رو مشخص کنیم. اینطوری وظیفه‌ی clean، که قبلا تعریف کردیم، پیش از وظیفه‌های داخل gulp.start اجرا میشه. وظیفه‌ها داخل Gulp به شکل همروند (concurrent) باهم اجرا میشه و هیچ ترتیبی که کدوم زودتر تموم میشه وجود نداره، بنابراین لازمه که مطمئن بشیم که clean قبل از بقیه اجرا شده.

پاییدنِ پرونده‌ها!

برای اینکه تغییرات پرونده‌ها رو زیرنظر بگیریم و وظیفه‌های لازم رو وقتی که تغییر کردن خودکار اجرا کنیم، باید اول یک وظیفه جدید تعریف کنیم، بعد با gulp.watch‍ تغییرات پرونده‌ها رو زیر نظر بگیریم:

gulp.task('watch', function() {

  // Watch .scss files
  gulp.watch('src/styles/**/*.scss', ['styles']);

  // Watch .js files
  gulp.watch('src/scripts/**/*.js', ['scripts']);

  // Watch image files
  gulp.watch('src/images/**/*', ['images']);

});

ما پرونده‌هایی که میخوایم زیر نظر بگیریم رو با استفاده از gulp.watch تعریف می‌کنیم. حالا می‌تونیم دستور $ gulp watch رو اجرا کنیم و با هر تغییری تو پرونده‌هامون، Gulp وظیفه‌اش رو انجام میده!

بارگیری خودکار صفحه در مرورگر

Gulp می‌تونه صفحه مرورگر شما رو وقتی پرونده‌ها تغییر میکنن خودش دوباره بارگیری کنه. فقط لازمه که وظیفه‌ی watch رو که بالا نوشتیم رو کمی تغییر بدیم و سرور LiveReload رو بهش اضافه کنیم:

gulp.task('watch', function() {

  // Create LiveReload server
  var server = livereload();

  // Watch any files in dist/, reload on change
  gulp.watch(['dist/**']).on('change', function(file) {
    server.changed(file.path);
  });

});
سرهم‌بندی کد

این کل پرونده gulp که نوشتیم:

// Load plugins
var gulp = require('gulp'),
    sass = require('gulp-ruby-sass'),
    autoprefixer = require('gulp-autoprefixer'),
    minifycss = require('gulp-minify-css'),
    jshint = require('gulp-jshint'),
    uglify = require('gulp-uglify'),
    imagemin = require('gulp-imagemin'),
    rename = require('gulp-rename'),
    clean = require('gulp-clean'),
    concat = require('gulp-concat'),
    notify = require('gulp-notify'),
    cache = require('gulp-cache'),
    livereload = require('gulp-livereload');

// Styles
gulp.task('styles', function() {
  return gulp.src('src/styles/main.scss')
    .pipe(sass({ style: 'expanded', }))
    .pipe(autoprefixer('last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'))
    .pipe(gulp.dest('dist/styles'))
    .pipe(rename({ suffix: '.min' }))
    .pipe(minifycss())
    .pipe(gulp.dest('dist/styles'))
    .pipe(notify({ message: 'Styles task complete' }));
});

// Scripts
gulp.task('scripts', function() {
  return gulp.src('src/scripts/**/*.js')
    .pipe(jshint('.jshintrc'))
    .pipe(jshint.reporter('default'))
    .pipe(concat('main.js'))
    .pipe(gulp.dest('dist/scripts'))
    .pipe(rename({ suffix: '.min' }))
    .pipe(uglify())
    .pipe(gulp.dest('dist/scripts'))
    .pipe(notify({ message: 'Scripts task complete' }));
});

// Images
gulp.task('images', function() {
  return gulp.src('src/images/**/*')
    .pipe(cache(imagemin({ optimizationLevel: 3, progressive: true, interlaced: true })))
    .pipe(gulp.dest('dist/images'))
    .pipe(notify({ message: 'Images task complete' }));
});

// Clean
gulp.task('clean', function() {
  return gulp.src(['dist/styles', 'dist/scripts', 'dist/images'], {read: false})
    .pipe(clean());
});

// Default task
gulp.task('default', ['clean'], function() {
    gulp.start('styles', 'scripts', 'images');
});

// Watch
gulp.task('watch', function() {

  // Watch .scss files
  gulp.watch('src/styles/**/*.scss', ['styles']);

  // Watch .js files
  gulp.watch('src/scripts/**/*.js', ['scripts']);

  // Watch image files
  gulp.watch('src/images/**/*', ['images']);

  // Create LiveReload server
  var server = livereload();

  // Watch any files in dist/, reload on change
  gulp.watch(['dist/**']).on('change', function(file) {
    server.changed(file.path);
  });

});

این پرونده رو می‌تونید تو gist هم ببینید. من این پیکربندی رو برای Grunt هم انجام دادم که می‌تونید برای مقایسه، تو همون gist ببینیدش.

اگر هر سوالی داشتید از فیلدهای نظردهی استفاده کنید.

تفاوت Warranty و guarantee

واژه گارانتی که در زبان فارسی (و حتی در کشورهای انگلیسی زبان) به اشتباه به معنی ضمانت تعویض دستگاه یا قطعات انگاشته می‌شود در حقیقت معنی متفاوتی دارد.
برای بررسی بیشتر باید با دو کلمه به ظاهر شبیه آشنا شویم: Warranty و guarantee
این دو واژه که به اشتباه معادل انگاشته می‌شوند در حقیقت دو معنای متفاوت دارند.
گارانتی (guarantee): یعنی تضمین برآورده شدن شرایط خاصی برای یک محصول، یا به عبارتی تضمین کیفیت محصول.
برای مثال: کارخانه سازنده تضمین می‌کند که ترمز این وسیله نقلیه در هر سرعتی بعد از سه ثانیه وسیله نقلیه را متوقف کند.

وارنتی Warranty: واژه وارنتی یعنی ضمانت تعویض قطعات وسیله در صورت نیاز در بازه زمانی خاص.
برای مثال: کارخانه سازنده تضمین می‌کند که تا یک سال پس از خرید، ترمز وسیله نقلیه را در صورت خراب شدن به صورت رایگان تعویض کند.
پس: ما عموما به اشتباه واژه گارانتی را به جای وارنتی به کار می‌بریم.

Categories:

تفاوت alias و alias_method در روبی

routes - Tue, 05/13/2014 - 00:05

تو روبی برای ایجاد نام مستعار برای متدها میشه از alias یا alias_method استفاده کرد. در نگاه اول ممکنه به نظر بیاد که این دو تا مثل هم هستن ولی در حقیقت یک تفاوت خیلی کوچک با هم دارن.

کد برای alias:
class Test
  def name
    puts 'Arash'
  end

  alias :sirname :name
end

Test.new.name # => Arash
Test.new.sirname # => Arash
کد برای alias_method:
class Test
  def name
    puts 'Arash'
  end

  alias_method :sirname, :name
end

Test.new.name # => Arash
Test.new.sirname # => Arash

تا اینجا که چیز خیلی خاصی دیده نمیشه. فقط اینکه تو alias از کاما استفاده نمی‌کنیم. این رفتار عادی و مورد انتظار از alias و alias_method است. در این موارد name و sirname هر دو خروجی یکسان دارن. اما اگه یک کلاس زیرمجموعه از Test درست کنیم چی؟

class Test
  def name
    puts 'Arash'
  end

  def self.do_rename
    alias :sirname :name
  end
end

class Example < Test
  def name
    puts 'Ernie'
  end
  do_rename
end

Example.new.name # => Ernie
Example.new.sirname # => Arash

اینجا sirname به کلاس والد اشاره می‌کنه. alisa زمانی که کد parse میشه مقداردهی میشه. موقع اجرای Test متد sirname با مقدار name پر میشه و این برای تمام کلاس‌های گرفته شده از Test هم درسته.

در طرف مقابل alias_method در همون حوزه‌ی self مقداردهی میشه:

class Test
  def name
    puts 'Arash'
  end

  def self.do_rename
    alias_method :sirname, :name
  end
end

class Example < Test
  def name
    puts 'Ernie'
  end

  do_rename
end

Example.new.name # => Ernie
Example.new.sirname # => Ernie

توضیح خاص دیگه فکر نکنم بخواد. کاملا روشن‌ه :)

Rails 4.1 ActiveRecord enums

routes - Fri, 04/18/2014 - 13:08

نسخه ۴.۱ ریلز به تازگی منتشر شده و امکانات جالب جدیدی داره. یکی از این امکانات ActiveRecord Enums هست، یک امکان خوب که ذخیره حالت‌های مختلف یک رکورد در مدل رو آسون میکنه.

مثلا فرض کنید که در برنامه‌تون یک مدل User دارین و هر کدوم از این کاربرها می‌تونین یک وضعیت به عنوان‌های registered و active یا blocked داشته باشن.

تو نسخه‌های قبلی اگر میخواستین این کار رو بکنید، احتمالا یک فیلد متنی یا عددی به دیتابیس اضافه می‌کردین و بعد هم چندتا scope توی مدل میذاشتین تا از جدول اطلاعات رو بگیرید. حالا همه چیز ساده‌تر شده. فقط لازمه که یک migration بنویسید و فقط فیلد لازم رو به جدول اضافه کنید:

class AddStatus < ActiveRecord::Migration
  def change
    add_column :users, :state, :integer
  end
end

و بعد هم ماکرو enum رو به کلاس User اضافه کنید:

class User
  enum state: [:registered, :active, :blocked]
end

به صورت پیش‌فرض وضعیت کاربر nil خواهد بود. ما می‌تونیم با اسم هر وضعیت یک کوئری بگیریم:

user = User.new
user.state
 # => nil

user.registered?
 # => false

user.state = :registered
user.registered?
 # => true

می‌تونیم مستقیما وضعیت کاربر رو بروزرسانی و ذخیره کنیم:

user.registered!
user.persisted?
 # => true
user.registered?
 # => true

همینطور به طور خودکار یک scope هم برای هر وضعیت داریم:

User.active
 # => #<ActiveRecord::Relation []>
User.registered
 # => #<ActiveRecord::Relation [#<User id: 7, status: 0...]>

حتی می‌تونیم به شکل مستقیم یک کاربر با وضعیتی که میخوایم بسازیم:

User.registered.create
 # => #<User id: 6, status: 1, ...>

ActiveRecord برای ذخیره وضعیت‌ها توی فیلد دیتابیس از عدد استفاده میکنه. اگر لازم باشه که یک وضعیت پیش‌فرض برای کاربر داشته باشیم (ینی کاربری که ساخته میشه مثلا وضعیت active داشته باشه و نه nil) میتونیم توی migration از کلید default استفاده کنیم:

class ChangeStatus < ActiveRecord::Migration
  def change
    change_column :users, :status, :integer, default: 1
  end
end

از الان به بعد تمام کاربرهای جدیدی که ساخته میشن وضعیت پیش‌فرض active رو خواهند داشت:

user = User.new
user.state
 # => "active"

توجه داشته باشین که برای اسم وضعیت‌ها از اسم‌های ستون‌های موجود در پایگاه داده یا متدهایی که قبلا استفاده کردین و یا کلیدهایی که مختص ریلز هست، استفاده نکنید. اگر اشتباها اینکار رو بکنید، ریلز خطا میده:

class User
  enum state: [:logger]
end
 # => ArgumentError: You tried to define an enum named "state" on the model "User",
 # but this will generate a class method "logger", 
 # which is already defined by Active Record.

چرا نباید از دکمه Snooze آلارم استفاده کرد

routes - Sat, 03/15/2014 - 18:39

تو ویدئو زیر به شکلی علمی توضیح میده که چرا نباید از امکان Snooze کردن آلارم استفاده کرد.

Don't Snooze

ح.ز.ب.ن (حجمش زیاد بود نگرفتم):

خلاصه اینکه اگه یک زمان خواب مرتب نداشته باشین آلارم ساعت باعث میشه چرخه خواب شما مختل بشه و زمانی که بدن لازم داره تا وضعیت‌تون رو به حالت سرحال تغییر بده رو کوتاه میکنه. استفاده از Snooze که مثلا هر ده دقیقه صدای زنگ درمیاد باعث میشه این چرخه حتی کوتاه‌تر بشه و همیشه بعد از بیدار شدن احساس خستگی بکنید و روز خوبی نداشته باشید. بهتر اینه که زمان خواب مرتبی تنظیم کنید و ساعتتون رو هم زمانی که باید بیدار بشید کوک کنید. بعد از یک هفته بدنتون خودش رو باهاش تطبیق میده و روز رو خیلی بهتر آغاز می‌کنید.

rdesktop

برای اتصال از راه دور  به سرورهای با سیستم عامل ویندوز برنامه‌های زیادی در سیستم عامل لینوکس وجود داره. برنامه خط‌فرمانی rdesktop یکی از این برنامه‌هاست.

این برنامه‌ها از پروتکل RDP که بوسیله مایکروسافت ایجاد شده برای ارتباط استفاده می‌کنند. نکته جالب اینجاست که این برنامه به نسبت remote desktop ویندوز پروتکل RDP رو به صورت کاملتر پیاده سازی کرده.

شکل کلی استفاده از این دستور به این صورته

rdesktop ip

وارد کردن نام کاربری و پسورد توی صفحه لاگین ویندوز کار سختیه مخصوصا اگه کلیپبرد فعال نباشه. با پارامترهای u و p میشه نام و کلمه عبور رو به سرور ارسال کرد.

rdesktop iprdesktop ip -u username -p pass

برای تغییر رزولوشن از پارامتر ‎-g استفاده می‌کنیم.

rdesktop ip -u username -p pass -g 1024x640

با پارامتر ‎-r یک ابزار رو در سیستم کلاینت به سرور تغیییر مسیر می‌دیم. و در نتیجه اون ابزار (کلیپ برد هارد و …) توی سرور هم دیده می‌شه و قابل استفاده است.

اشتراک کلیپ‌برد کلاینت با سرور :

rdesktop ip  -r clipboard:PRIMARYCLIPBOARD

اشتراک دایرکتوری ‎/home در سرور ویندوز.

rdesktop ip  -r disk:home=/home

برای فشرده سازی ارتباط از پارامتر ‎-z استفاده می‌کنیم.

از پارامتر ‎-P (حرف پی بزرگ) برای کش کردن عکس‌های bitmap استفاده می‌شه. استفاده از این پارامتر پهنای باند مصرفی رو به میزان زیادی کاهش می‌ده.

rdesktop -u administrator -p passwords.txt 192.168.0.100

پارامتر ‎-m رویدادهای حرکت موس رو به سرور ارسال نمی‌کنه در نتیجه استفاده از این آپشن پهنای باند مصرفی رو کاهش می‌ده و سرعت رو افزایش می‌ده.

پارامتر ‎ -a عمق رنگ رو مشخص می‌کنه. هر چه عمق رنگ رو کمتر انتخاب کنید سرعت ارتباط زیادتر و کیفیت تصویر کمتر میشه.

پارامتر ‎ -f پنجره رو به صورت full screen نمایش می‌ده. برای خروج از حالت تمام صفحه دکمه‌های alt + ctrl + enter رو باید بزنید.

Categories:

سخت‌افزار‌های آزاد قسمت هفتم (ایستگاه رادیو با مجوز GNU)

توی نوشته‌های قبل (قسمت اول، دوم، سوم، چهارم، پنجم ، ششم) در مورد چند تا سخت‌افزار آزاد نوشتم. توی این قسمت از ایستگاه رادیو آزاد مینویسم.

رادیو گنو پروژه‌ای قدیمی است. شروع این پروژه حدود ده سال پیش بوده و هدف اصلی پروژه ساخت ایستگاه رادیویی بوده که بیشتر کارها رو با نرم‌افزار انجام بده و کمترین نیاز به سخت‌افزار داشته باشه. در حقیقت توسعه دهنده‌های رادیو گنو از روش SDR و یا software defined radio برای پیاده سازی این رادیو استفاده کردند. در روش SDR به جای به جای ساخت همه تجهیزات مورد نیاز یک ایستگاه رادیویی (میکسر، فیلتر، آمپلی‌فایر و …) به صورت سخت‌افزاری از پی‌سی برای پیاده سازی این امکانات بصورت نرم‌افزاری استفاده می‌کنند و خروجی صوتی نهایی رو با فرستنده‌های رادیویی در طول موج‌های متفاوت ارسال می‌کنند.

پروژه گنورادیو سخت افزارهای متعددی رو پشتیبانی می‌کنه مثل سخت‌افزار USRP و یا funcubedongle .

Categories:

مدیریت پارامترهای ارسالی به اسکریپت‌های بش با دستور getopts

در برنامه‌های خط فرمانی cli کاربر با استفاده از پارامتر با برنامه و یا اسکریپت ارتباط برقرار می‌کنه بنابراین یکی از اولین قدمهای نوشتن یک اسکریپت حرفه‌ای اینه که پارامترهای ارسال شده به اسکریپت رو بصورت کاملا حرفه‌ای بررسی کنید. دستور getopts یکی از برنامه‌های خیلی خوب برای مدیریت پارامترهای ارسالی به اسکریپته که به زیباترین شکل ممکن آپشن‌های را بررسی و پارس میکنه. اما قبل از بررسی این دستور بهتره تا حدودی با پارامترهای ارسالی به برنامه‌های cli آشنا بشیم.
در لینوکس پارامترهایی که به یک دستور یا اسکریپت بش ارسال می‌کنیم به سه صورت میتونه باشه.
آپشن‌های تک کاراکتری ( single-character options) مثل ‎-a در دستور ls
آپشن‌های طولانی سبگ گنو (GNU-style long option) مثل ‎- -all
آپشن‌های طولانی سبک XF86 یا (XF86-style long options) مثل ‎-all

برنامه getops قادر به بررسی آپشن‌های طولانی سبگ گنو و آپشن‌های طولانی سبک XF86 نیست و فقط میتونه پارامترهای رو به شکل تک حرفی ببینه.

این مثالها رو در نظر بگیرید.

ls -las
ls -l -a -s
ls -la -s
ls -l -as

 

همونطور که می‌دونید این چهار دستور یک نتیجه رو باید نشان بده یعنی چه آرگومان‌ها به هم چسبیده باشند و چه جدا باشند نتیجه باید ثابت باشه! خوب کاملا مشخصه که بررسی حالت‌های مختلفی که ممکنه پارامترها به یک دستور ارسال بشه کار فوق العاده سختی می‌تونه باشه و اینجاست که دستور getopts به کمک ما میاد.

این کد رو یک نگاهی بهش بکنید تا ببینیم چجوری باید از getopts استفاده کنیم.

#!/bin/bash
while getopts "abc:d:" OPTION ; do
   case $OPTION in
      # help
      a)
         echo "a!"
      ;;
      b)
         echo "b!"
      ;;
      c)
         echo "c = $OPTARG" 
      ;;
      d)
         echo "d = $OPTARG"
   esac
done

از اونجا که پارامترهای ارسالی به اسکریپت ما ممکنه بیش از یکی باشه از یک حلقه while استفاده می‌کنیم تا تک تک پارامترها رو بررسی کنیم

while getopts "abc:d:" OPTION ; do

عبارت abc:d:‎  به getopts میگه که پارامترهای اسکریپت اینهاست

  • -a
  • -b
  • -c param
  • -d param

حرف a به تنهایی حرف b به تنهایی حرف c به همراه یک پارامتر و بلاخره حرف d به همراه یک پارامتر اضافه!  توجه دارید که هر دو نقطه جلوی یک پارامتر به معنی یک پارامتر اضافه است! در هر بار اجرای getopts یکی از پارامترهای ارسالی به اسکریپت خونده میشه و توی متغییر OPTION ریخته میشه و ما با استفاده از یک حلقه case این پارامترها رو دونه دونه بررسی می‌کنیم!  اگه پارامتر اضافه‌ای داشته باشیم توی متغییر OPTARG ریخته میشه.

اگر اسکریپت رو با همراه پارامترها اجرا کنیم نتیجه این خواهد بود.

$ ./bash.sh -ab -c param1 -dparam2
a!
b!
c = param1
d = param2

 

Categories:

Pages

Trigup Fanap O'Reilly Media
iranserver

زبان‌ها