用named_scope代替繁瑣的finder

本文介绍了一种使用Rails中named_scope的优雅方式来替代繁琐的find方法。通过对比两种不同的PostsController实现,展示了如何简化代码并提高其可读性和美观度。
原文參考:[url]http://rails-bestpractices.com/posts/1-move-finder-to-named_scope[/url]
壞習慣:
下面的代碼看了就讓人感覺不舒服,不但寫的繁雜,而且也不美觀...
class PostsController < ApplicationController
def index
@published_posts = Post.find(:all, :conditions => { :state => 'published' },
:limit => 10,
:order => 'created_at desc')

@draft_posts = Post.find(:all, :conditions => { :state => 'draft' },
:limit => 10,
:order => 'created_at desc')
end
end


我們可以用name_scope來拯救它...
清新一個伶俐一個燦爛一個,大嘴巴子抽Y的:[img]/images/guest_book/8.gif[/img]
class PostsController < ApplicationController
def index
@published_posts = Post.published
@draft_posts = Post.draft
end
end

class Post < ActiveRecord::Base
named_scope :published, :conditions => { :state => 'published' },
:limit => 10,
:order => 'created_at desc'
named_scope :draft, :conditions => { :state => 'draft' },
:limit => 10,
:order => 'created_at desc'
end
`of_get_named_gpiod_flags()` 是 Linux 内核中用于从设备树(Device Tree)解析 GPIO 描述符及其标志的核心函数,属于 GPIO 子系统的设备树接口。其核心逻辑是:**通过设备树属性名获取 GPIO 描述符,并返回其标志位(如电平有效方式)**。以下是其完整源码及关键细节(基于 Linux 5.x 内核): --- ### **完整源码实现** ```c #include <linux/gpio/consumer.h> #include <linux/of.h> #include <linux/err.h> /** * of_get_named_gpiod_flags() - 从设备树获取带标志的 GPIO 描述符 * @np: 设备树节点指针 * @propname: GPIO 属性名(如 "reset-gpios") * @index: 多 GPIO 属性中的索引(通常为 0) * @flags: 输出参数,返回 GPIO 标志(如 GPIO_ACTIVE_HIGH) * * 返回:成功时返回 gpio_desc 指针,失败时返回错误指针(ERR_PTR)。 */ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, const char *propname, int index, enum of_gpio_flags *flags) { int gpio_num; struct gpio_desc *desc; // 1. 调用 of_get_named_gpio_flags() 解析设备树属性 gpio_num = of_get_named_gpio_flags(np, propname, index, flags); if (gpio_num < 0) { return ERR_PTR(gpio_num); // 返回错误指针(如 -ENODEV) } // 2. 通过 GPIO 编号获取描述符 desc = gpio_to_desc(gpio_num); if (!desc) { return ERR_PTR(-ENXIO); // 编号无效 } return desc; } EXPORT_SYMBOL_GPL(of_get_named_gpiod_flags); ``` --- ### **关键依赖函数:of_get_named_gpio_flags()** ```c // 简化版(实际实现见前文分析) int of_get_named_gpio_flags(struct device_node *np, const char *propname, int index, enum of_gpio_flags *flags) { const __be32 *prop; u32 pflags; int na; // 1. 查找属性 prop = of_get_property(np, propname, &pflags); if (!prop) { return -ENODEV; // 属性不存在 } // 2. 检查属性长度 na = of_property_count_u32_elems(np, propname); if (na < 0 || na <= index * 3 + 2) { return -EINVAL; // 索引越界或格式错误 } // 3. 解析 GPIO 编号和标志 gpio_num = be32_to_cpup(prop + index * 3 + 1); if (flags) { *flags = be32_to_cpup(prop + index * 3 + 2); } return gpio_num; } ``` --- ### **核心逻辑解析** #### 1. **设备树属性解析** - **函数调用链**: - `of_get_named_gpiod_flags()` → `of_get_named_gpio_flags()` → `of_get_property()` - 最终从设备树节点 `np` 中解析属性 `propname`(如 `"reset-gpios"`)。 - **属性格式要求**: - 每个 GPIO 需 3 个 `u32` 值:`<&phandle GPIO_NUMBER FLAGS>` - 示例:`reset-gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>` #### 2. **GPIO 编号转换** - **`gpio_num` 到 `gpio_desc`**: - `of_get_named_gpio_flags()` 返回原始 GPIO 编号(如 `12`)。 - `gpio_to_desc()` 将编号转换为内核统一的 `gpio_desc` 描述符,便于后续操作(如 `gpiod_set_value()`)。 #### 3. **标志位传递** - **`flags` 参数**: - 通过 `of_get_named_gpio_flags()` 解析设备树中的标志(如 `GPIO_ACTIVE_LOW`)。 - 调用者可据此配置 GPIO 的电平有效方式(如 `gpiod_set_active_low()`)。 --- ### **错误处理** | 错误码 | 触发条件 | 说明 | |--------------|-----------------------------------|--------------------------| | `-ENODEV` | 属性不存在 | 设备树未定义该 GPIO 属性 | | `-EINVAL` | 索引越界或属性格式错误 | 例如多 GPIO 属性长度不足 | | `-ENXIO` | GPIO 编号无效 | 编号超出控制器范围 | --- ### **典型使用场景** #### 1. **获取复位引脚并配置标志** ```c struct device_node *np = dev->of_node; enum of_gpio_flags flags; struct gpio_desc *reset_gpio; // 解析 "reset-gpios" 属性的第 0 个 GPIO reset_gpio = of_get_named_gpiod_flags(np, "reset-gpios", 0, &flags); if (IS_ERR(reset_gpio)) { dev_err(dev, "Failed to get reset GPIO: %ld\n", PTR_ERR(reset_gpio)); return PTR_ERR(reset_gpio); } // 根据标志配置电平有效方式 if (flags & OF_GPIO_ACTIVE_LOW) { gpiod_set_active_low(reset_gpio, true); } // 使用 GPIO gpiod_set_value(reset_gpio, 1); // 拉高复位引脚 ``` #### 2. **设备树属性示例** ```dts sensor@1234 { compatible = "vendor,sensor"; reset-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>; // 低电平有效 enable-gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>; // 高电平有效 }; ``` --- ### **与 `gpiod_get()` 的关系** | 函数 | 行为差异 | 适用场景 | |-------------------------------|-----------------------------------|------------------------------| | `gpiod_get()` | 默认属性名 `"gpios"`,索引 0 | 简单场景(单 GPIO 属性) | | `of_get_named_gpiod_flags()` | 自定义属性名和索引,返回标志 | 复杂场景(多 GPIO 或需标志) | **示例对比**: ```c // 使用 gpiod_get()(默认属性名 "gpios") gpio = gpiod_get(dev, NULL, 0); // 使用 of_get_named_gpiod_flags()(自定义属性名) gpio = of_get_named_gpiod_flags(np, "enable-gpios", 0, &flags); ``` --- ### **性能优化** 1. **属性缓存**: - 内核可能缓存频繁访问的设备树属性,减少重复解析开销。 2. **描述符复用**: - `gpio_desc` 通过引用计数管理,避免重复分配内存。 --- ### **与 `devm_of_get_named_gpiod_flags()` 的区别** | 函数 | 资源管理方式 | 适用场景 | |---------------------------------------|----------------------------|------------------------------| | `of_get_named_gpiod_flags()` | 需手动调用 `gpiod_put()` | 短期使用的 GPIO | | `devm_of_get_named_gpiod_flags()` | 自动释放(设备卸载时) | 驱动生命周期内的 GPIO | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值