ocs_doc_api: Phase 3-ii — typed AttributeDefinition create (Phase 3 complete)

- CreateAttributeDefinition(AttributeDefinitionSpec) op (append-only).
- backend add_attribute_definition (ATTDEF tag/prompt/default/insertion/height/rotation).
- facade create_attribute_definition; entity_kind_name AttributeDefinition/AttributeEntity.
- spec AttributeDefinition family; api_reference + binding_schema regenerated; mocks + baseline.
- Test phase3ii_create_attribute_definition -> 614 host lib + 3 consistency green.
This commit is contained in:
Sebastian committed 2026-09-06 12:43:34 +02:00
1 parent 8d8c120880
commit f8ae54a351
14 files changed
+128 -3

No files matched your search

+3
View File
@@ -72,6 +72,9 @@ pub trait DocApiBackend {
/// Add a 3-point angular `DIMENSION`; returns the fresh `ObjectId`.
fn add_dimension_angular(&mut self, spec: &crate::ops::DimensionAngularSpec) -> ApiResult<ObjectId>;
/// Add an `ATTDEF` (in-block attribute definition); returns the fresh `ObjectId`.
fn add_attribute_definition(&mut self, spec: &crate::ops::AttributeDefinitionSpec) -> ApiResult<ObjectId>;
/// A dimension's measured value (distance for linear/radius, degrees for angular).
fn dimension_measurement(&self, id: ObjectId) -> ApiResult<f64>;
+6
View File
@@ -287,6 +287,12 @@ pub fn apply_op<B: DocApiBackend>(b: &mut B, op: Operation) -> ApiResult<Receipt
b.finalize_op();
OpOutcome::NewId(id)
}
Operation::CreateAttributeDefinition(spec) => {
b.push_undo(name);
let id = b.add_attribute_definition(spec)?;
b.finalize_op();
OpOutcome::NewId(id)
}
};
Ok(Receipt {
outcome: Some(outcome),
+14
View File
@@ -631,6 +631,20 @@ impl EntityCollection {
Ok(Entity::new(self.session.clone(), id))
}
/// Create an ATTDEF (in-block attribute definition): tag/prompt/default at a point.
pub fn create_attribute_definition(&self, tag: &str, prompt: &str, default_value: &str, insertion_point: [f64; 3], height: f64, rotation: f64) -> ApiResult<Entity> {
let receipt = self.session.apply_op(Operation::CreateAttributeDefinition(crate::ops::AttributeDefinitionSpec {
tag: tag.to_string(),
prompt: prompt.to_string(),
default_value: default_value.to_string(),
insertion_point,
height,
rotation,
}))?;
let id = receipt.outcome.and_then(|o| o.new_id()).ok_or_else(|| ApiError::Transport("create_attribute_definition returned no id".into()))?;
Ok(Entity::new(self.session.clone(), id))
}
/// Place a block reference (`INSERT`) for `block_name` (must exist).
pub fn create_insert(&self, block_name: &str, insert_point: [f64; 3], scale: f64, rotation: f64) -> ApiResult<Entity> {
let receipt = self.session.apply_op(Operation::CreateInsert(crate::ops::InsertSpec {
@@ -154,6 +154,14 @@ Block reference. Place an existing BlockRecord by name; transform moves its inse
- **attributes**() -> `Vec<(String, String)>` — query `GetAttributes`
- **set_attribute**(tag: &str, value: &str) -> `()` — op `SetAttribute`
## `Entity` (acadrust `AttributeDefinition`, collection `entities`)
In-block attribute definition (ATTDEF): tag/prompt/default at an insertion point.
### Constructors (`doc.entities()`)
- **create_attribute_definition**(tag: &str, prompt: &str, default_value: &str, insertion_point: [f64; 3], height: f64, rotation: f64) -> `Entity` — `CreateAttributeDefinition`
## `Entity` (acadrust `Viewport`, collection `entities`)
Paper-space viewport: a width×height window at center looking at view_target with view_height zoom. bounds = center ± w/2,h/2; transform moves center.
@@ -335,6 +335,13 @@
],
"name": "Insert"
},
{
"acadrust_variant": "AttributeDefinition",
"collection": "entities",
"handle": "Entity",
"methods": [],
"name": "AttributeDefinition"
},
{
"acadrust_variant": "Viewport",
"collection": "entities",
+3 -1
View File
@@ -7,7 +7,7 @@
use serde::{Deserialize, Serialize};
use crate::id::ObjectId;
use crate::ops::{BoolOp, Curve2Spec, DimensionAngularSpec, DimensionRadialSpec, DimensionSpec, EntitySpec, HatchSpec, InsertSpec, MTextSpec, PlacementSpec, RasterImageSpec, SolidPrimitive, TextSpec, ViewportSpec};
use crate::ops::{AttributeDefinitionSpec, BoolOp, Curve2Spec, DimensionAngularSpec, DimensionRadialSpec, DimensionSpec, EntitySpec, HatchSpec, InsertSpec, MTextSpec, PlacementSpec, RasterImageSpec, SolidPrimitive, TextSpec, ViewportSpec};
/// A typed write operation (plan §5). Each variant is ONE atomic host call = one
/// undo step. Append new variants at the END only.
@@ -52,4 +52,6 @@ pub enum Operation {
CreateDimensionRadius(DimensionRadialSpec),
CreateDimensionDiameter(DimensionRadialSpec),
CreateDimensionAngular(DimensionAngularSpec),
// attribute definitions
CreateAttributeDefinition(AttributeDefinitionSpec),
}
+13
View File
@@ -136,6 +136,18 @@ pub struct DimensionAngularSpec {
pub arc_location: [f64; 3],
}
/// Construction spec for an `ATTDEF` (attribute definition): the tag, prompt,
/// and default value for an in-block attribute, at an insertion point.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AttributeDefinitionSpec {
pub tag: String,
pub prompt: String,
pub default_value: String,
pub insertion_point: [f64; 3],
pub height: f64,
pub rotation: f64,
}
/// Construction spec for a `RASTER_IMAGE`: an image file placed at
/// `insertion_point` with per-pixel world-unit vectors `u_vector`/`v_vector` and
/// pixel `size` (width, height). The host auto-registers the ImageDefinition.
@@ -210,6 +222,7 @@ impl crate::gen::Operation {
CreateDimensionRadius(_) => "CreateDimensionRadius",
CreateDimensionDiameter(_) => "CreateDimensionDiameter",
CreateDimensionAngular(_) => "CreateDimensionAngular",
CreateAttributeDefinition(_) => "CreateAttributeDefinition",
}
}
}