编程

在 Sinatra 中使用 RESTful

最近在学习Sinatra。今天遇到了关于RESTful的问题,用过Rails的各位应该都对这个不陌生了,不过重量级的Rails有内置helper帮我们在模板里生成那些东西,轻量级的Sinatra可不会,我们要自己动手。

仿照Rails,在views模板中加入了 <input type="hidden" name="_method" value="put"> ,然后submit一下试试,然后发现还是被判断为一个post请求……

上网查了资料,说是如果用的是Modular风格的话,必须自己动手加入 use Rack::MethodOverride 。试了下,果然可以。

但是又觉得这个方法太傻了一点,于是又在Sinatra官网仔细晃了一圈,发现原来settings里有这一项 :method_override ,加入代码,搞定。

app.rb:

# encoding: utf-8
require "sinatra/base"
require "sinatra/contrib"
require "slim"

class RestTry < Sinatra::Base
  set :method_override => true
  register Sinatra::Contrib

  route :get, "/" do
    slim :rest, :locals => { :method => request.request_method }
  end

  run!
end

rest.slim :

doctype 5
html
  head
    meta charset="utf-8"
    title Sinatra REST Trying
  body
    p Method: #{method}
    section#get
      form action="." method="get"
        input type="submit" value="GET"
    section#post
      form action="." method="post"
        input type="submit" value="POST"
    section#put
      form action="." method="post"
        input type="hidden" name="_method" value="put"
        input type="submit" value="PUT"
    section#patch
      form action="." method="post"
        input type="submit" value="PATCH"
    section#delete
      form action="." method="post"
        input type="submit" value="DELETE"
    section#options
      form action="." method="post"
        input type="submit" value="OPTIONS"
    section#custom
      form action="." method="post"
        input type="submit" value="CUSTOM"

Rewind Track Wiki

1. 概述

1.1 起源

本项目完全基于个人兴趣,从 Rewind BBS 衍生而来。

“Track” 这个名字很容易引起误解,让人误以为这是一个 “BugTracking” 系统,其实并非如此。事实上当我最初开始打理自己的个人网站时,我在网站上留了一个叫 “Track” 的链接。这个链接的目的是为了陈列自己的设计作品,不论优劣,只是为了记录自己的生涯,就想家庭相册一样的感觉。

但是后来我渐渐地远离了设计师的道路,尽管仍然专注于 HTML/CSS 技术,却比以往更多地偏向于编写代码,本就浅薄的设计功底很快也就完全荒废殆尽了,这个陈列作品的角落也完全荒废了。

然而,有一件事一直让我放不下。因为作为一个陈列室,必定要有一个主页来列出所有的陈列对象。我最初是打算每次有新的作品加入时,手工修改静态的 HTML主页(我一开始就预想到很少会有更新),然而我却一直懒得给这个主页做一个详细的设计,最后在网站搬迁时,索性就把这个只有HTML没有半个字节 CSS和JS的主页都删了,留了个 Nginx 的 autoindex 页面出来。

于是最近,虽然我还是没有任何新的设计作品加入,但我决定要写这样一个简单的程序,动态地管理这个主页。如果这个网站最终无法陈列我的设计,那好歹让它陈列一下它自己好了……

1.2 需求概述

目前有2套方案,暂未最终决定

  • 方案1: 完全基于文件系统,没有任何额外的数据源。根据文件系统下的目录结构进行整理归档。这套方案比较简单,而且刚好可以帮助我练习一些平时不太熟悉的模块使用。不过最终的展示效果如何仍是疑问。
  • 方案2: 基于简单的 SQLite 数据库,添加陈列作品时人工录入必须的数据,并最终根据这些数据整理归档。这套方案灵活性更高,但是复杂度也较高,而且是否有必要也还是个问题……

让 Rails 3.1 默认使用Sass

因为比起用符号(大括号)控制的代码层次,更喜欢清晰的缩进式层次,因此想把Rails默认的SCSS改成SASS,希望通过诸如 rails g scaffold sth 生成出来的样式文件是Sass格式而非Scss格式。

在Google上奋斗了2个小时,除了在Stackflow上找到一篇文让我还略受启发外(但这篇文中许多人提出了许多种不同的解决方法,不知为何我用下来居然全都失败了),其他的几乎很难找到。

然后我开始读railties的源码……研究了半天generator,一无所获……最后都找到base.rb里去了。此时我开始意识到可能方向发生了错误,转而往更高层的方向寻找,最后终于在sass-rails/lib/sass/railtie.rb中找到了

config.sass.preferred_syntax = :scss

这行代码跟Stackflow网站上某人提出的办法相差无几,于是按照他的方法放入我的rails应用的/config/application.rb中,就在Application类中,跟在其他config.xxx后面,把:scss改成:sass,然后运行rails g scaffold orz,果然见到invoke sass,狂喜~

require File.expand_path('../boot', __FILE__)

require 'rails/all'

if defined?(Bundler)
  Bundler.require(*Rails.groups(:assets => %w(development test)))
end

module MyApplicationName
  class Application < Rails::Application
    config.encoding = "utf-8"
    config.filter_parameters += [:password]
    config.assets.enabled = true
    config.assets.version = '1.0'
    config.sass.preferred_syntax = :sass
  end
end

WPF使用System.Windows.OpenFileDialog选择文件夹

这几天在重温C#.Net-WPF,拿个以前废弃的项目练练手,其中遇到一个问题:

WPF自身的命名空间System.Windows中没有打开文件夹的对话框,只有OpenFileDialog可以打开文件。

网上搜了很多帖子,无外乎三种答案

  1. 使用以前WinForm的FolderBrowserDialog:为了避免命名空间冲突导致的代码繁琐(两边都有OpenFileDialog)以及出于一些洁癖的原因,我这次决定坚决不使用WinForm,反正自己做项目也没工期什么的,大不了不做了~
  2. 扩写System.Windows.OpenFileDialog:要么自己扩写,要么用一些别人写好的开源组件,一个是太麻烦,另一个心里总觉得不太舒服
  3. 使用微软官方的扩展包Microsoft.WindowsAPICodePack:这个看起来很不错,但是也有缺点,就是完全要求Windows版本>=6.0,而公司的电脑还是杯具的5.1,只能放弃

正在纠结之际,国外著名社区 Stack Overflow 上看到这么一篇帖子:

原帖地址

一位大佬想出了一个看起来很orz的方法,不过反正也没其他解决方案,姑且一试。

这位大佬将Filter设置成一个非常非常长的扩展名从而起到隐藏所有文件的目的:

openFileDialog1.Filter = "folders|*.neverseenthisfile"

然后把文件名设为一个”r”换行符来骗过OpenFileDialog,这样只要不改动文件名就能直接按打开按钮。当然同时还需要把CheckFileExists给false掉……

我修改了他的原型代码后得到了如下版本:

OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "folders|*.sado;fjsdal;fj";
ofd.FileName = "r";
ofd.CheckFileExists = false;
ofd.CheckPathExists = true;
ofd.ValidateNames = false;
if (ofd.ShowDialog() == true)
{
	ofd.FileName = ofd.FileName.TrimEnd('r');
	int lastSeparatorIndex = ofd.FileName.LastIndexOf('\');
	ofd.FileName = ofd.FileName.Remove(lastSeparatorIndex);
	txtCOutputPath.Text = ofd.FileName;
}

运行后成功取到了目录,并且哪怕不当心在文件文本框里输入了内容也可以正常工作了。本以为事情到此为止,我甚至都把这篇博文发表了出来(第一稿是到这行的前一个句号就结束的),到家后再试才发现家里的娜娜不买账!!!

仔细研究后,发现貌似娜娜不认ValidateNames属性,不论这个值是true还是false,她一定会检查文件名是否合法……好在她并不在意文件是否真的存在,所以代码稍加修改还是可以用:

OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = CoffeeScript._ofdOutputFilter;
ofd.FileName = "Filename will be ignored";
ofd.CheckFileExists = false;
ofd.CheckPathExists = true;
//ofd.ValidateNames = false;
if (ofd.ShowDialog() == true)
{
	//ofd.FileName = ofd.FileName.TrimEnd('r');
	int lastSeparatorIndex = ofd.FileName.LastIndexOf('\');
	ofd.FileName = ofd.FileName.Remove(lastSeparatorIndex);
	txtCOutputPath.Text = ofd.FileName;
	return true;
}
return false;

不过这种做法还是有一定问题的,如果用户不当心选中了一个文件夹,那他后面的麻烦就大了……看来这个问题还需要再研究一下……